Header And Logo

PostgreSQL
| The world's most advanced open source database.

Defines | Functions

command.c File Reference

#include "postgres_fe.h"
#include "command.h"
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "portability/instr_time.h"
#include "libpq-fe.h"
#include "pqexpbuffer.h"
#include "dumputils.h"
#include "common.h"
#include "copy.h"
#include "describe.h"
#include "help.h"
#include "input.h"
#include "large_obj.h"
#include "mainloop.h"
#include "print.h"
#include "psqlscan.h"
#include "settings.h"
#include "variables.h"
Include dependency graph for command.c:

Go to the source code of this file.

Defines

#define DEVTTY   "/dev/tty"
#define PARAMS_ARRAY_SIZE   8
#define DEFAULT_SHELL   "/bin/sh"

Functions

static backslashResult exec_command (const char *cmd, PsqlScanState scan_state, PQExpBuffer query_buf)
static bool do_edit (const char *filename_arg, PQExpBuffer query_buf, int lineno, bool *edited)
static bool do_connect (char *dbname, char *user, char *host, char *port)
static bool do_shell (const char *command)
static bool do_watch (PQExpBuffer query_buf, long sleep)
static bool lookup_function_oid (PGconn *conn, const char *desc, Oid *foid)
static bool get_create_function_cmd (PGconn *conn, Oid oid, PQExpBuffer buf)
static int strip_lineno_from_funcdesc (char *func)
static void minimal_error_message (PGresult *res)
static void printSSLInfo (void)
backslashResult HandleSlashCmds (PsqlScanState scan_state, PQExpBuffer query_buf)
static char * read_connect_arg (PsqlScanState scan_state)
static char * prompt_for_password (const char *username)
static bool param_is_newly_set (const char *old_val, const char *new_val)
void connection_warnings (bool in_startup)
void SyncVariables (void)
void UnsyncVariables (void)
static bool editFile (const char *fname, int lineno)
int process_file (char *filename, bool single_txn, bool use_relative_path)
static const char * _align2string (enum printFormat in)
bool do_pset (const char *param, const char *value, printQueryOpt *popt, bool quiet)

Define Documentation

#define DEFAULT_SHELL   "/bin/sh"

Definition at line 2533 of file command.c.

#define DEVTTY   "/dev/tty"

Referenced by exec_command().

#define PARAMS_ARRAY_SIZE   8

Function Documentation

static const char* _align2string ( enum printFormat  in  )  [static]

Definition at line 2210 of file command.c.

References PRINT_ALIGNED, PRINT_HTML, PRINT_LATEX, PRINT_LATEX_LONGTABLE, PRINT_NOTHING, PRINT_TROFF_MS, PRINT_UNALIGNED, and PRINT_WRAPPED.

Referenced by do_pset().

{
    switch (in)
    {
        case PRINT_NOTHING:
            return "nothing";
            break;
        case PRINT_UNALIGNED:
            return "unaligned";
            break;
        case PRINT_ALIGNED:
            return "aligned";
            break;
        case PRINT_WRAPPED:
            return "wrapped";
            break;
        case PRINT_HTML:
            return "html";
            break;
        case PRINT_LATEX:
            return "latex";
            break;
        case PRINT_LATEX_LONGTABLE:
            return "latex-longtable";
            break;
        case PRINT_TROFF_MS:
            return "troff-ms";
            break;
    }
    return "unknown";
}

void connection_warnings ( bool  in_startup  ) 

Definition at line 1732 of file command.c.

References _, _psqlSettings::db, _psqlSettings::notty, PQparameterStatus(), printSSLInfo(), _psqlSettings::progname, pset, _psqlSettings::quiet, server_version, snprintf(), and _psqlSettings::sversion.

Referenced by do_connect(), and main().

{
    if (!pset.quiet && !pset.notty)
    {
        int         client_ver = PG_VERSION_NUM;

        if (pset.sversion != client_ver)
        {
            const char *server_version;
            char        server_ver_str[16];

            /* Try to get full text form, might include "devel" etc */
            server_version = PQparameterStatus(pset.db, "server_version");
            if (!server_version)
            {
                snprintf(server_ver_str, sizeof(server_ver_str),
                         "%d.%d.%d",
                         pset.sversion / 10000,
                         (pset.sversion / 100) % 100,
                         pset.sversion % 100);
                server_version = server_ver_str;
            }

            printf(_("%s (%s, server %s)\n"),
                   pset.progname, PG_VERSION, server_version);
        }
        /* For version match, only print psql banner on startup. */
        else if (in_startup)
            printf("%s (%s)\n", pset.progname, PG_VERSION);

        if (pset.sversion / 100 > client_ver / 100)
            printf(_("WARNING: %s major version %d.%d, server major version %d.%d.\n"
                     "         Some psql features might not work.\n"),
                 pset.progname, client_ver / 10000, (client_ver / 100) % 100,
                   pset.sversion / 10000, (pset.sversion / 100) % 100);

#ifdef WIN32
        checkWin32Codepage();
#endif
        printSSLInfo();
    }
}

static bool do_connect ( char *  dbname,
char *  user,
char *  host,
char *  port 
) [static]

Definition at line 1574 of file command.c.

References _, CONNECTION_OK, connection_warnings(), _psqlSettings::cur_cmd_interactive, _psqlSettings::db, free, _psqlSettings::getPassword, is_absolute_path, NoticeProcessor(), _psqlSettings::notty, NULL, param_is_newly_set(), PARAMS_ARRAY_SIZE, pg_malloc(), pg_strdup(), PQconnectdbParams(), PQconnectionNeedsPassword(), PQdb(), PQerrorMessage(), PQfinish(), PQhost(), PQpass(), PQport(), PQsetNoticeProcessor(), PQstatus(), PQuser(), _psqlSettings::progname, prompt_for_password(), pset, psql_error(), _psqlSettings::quiet, SyncVariables(), TRI_NO, TRI_YES, and values.

Referenced by exec_command().

{
    PGconn     *o_conn = pset.db,
               *n_conn;
    char       *password = NULL;

    if (!o_conn && (!dbname || !user || !host || !port))
    {
        /*
         *  We don't know the supplied connection parameters and don't want
         *  to connect to the wrong database by using defaults, so require
         *  all parameters to be specified.
         */
        psql_error("All connection parameters must be supplied because no "
                   "database connection exists\n");
        return false;
    }

    if (!dbname)
        dbname = PQdb(o_conn);
    if (!user)
        user = PQuser(o_conn);
    if (!host)
        host = PQhost(o_conn);
    if (!port)
        port = PQport(o_conn);

    /*
     * If the user asked to be prompted for a password, ask for one now. If
     * not, use the password from the old connection, provided the username
     * has not changed. Otherwise, try to connect without a password first,
     * and then ask for a password if needed.
     *
     * XXX: this behavior leads to spurious connection attempts recorded in
     * the postmaster's log.  But libpq offers no API that would let us obtain
     * a password and then continue with the first connection attempt.
     */
    if (pset.getPassword == TRI_YES)
    {
        password = prompt_for_password(user);
    }
    else if (o_conn && user && strcmp(PQuser(o_conn), user) == 0)
    {
        password = pg_strdup(PQpass(o_conn));
    }

    while (true)
    {
#define PARAMS_ARRAY_SIZE   8
        const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
        const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));

        keywords[0] = "host";
        values[0] = host;
        keywords[1] = "port";
        values[1] = port;
        keywords[2] = "user";
        values[2] = user;
        keywords[3] = "password";
        values[3] = password;
        keywords[4] = "dbname";
        values[4] = dbname;
        keywords[5] = "fallback_application_name";
        values[5] = pset.progname;
        keywords[6] = "client_encoding";
        values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
        keywords[7] = NULL;
        values[7] = NULL;

        n_conn = PQconnectdbParams(keywords, values, true);

        free(keywords);
        free(values);

        /* We can immediately discard the password -- no longer needed */
        if (password)
            free(password);

        if (PQstatus(n_conn) == CONNECTION_OK)
            break;

        /*
         * Connection attempt failed; either retry the connection attempt with
         * a new password, or give up.
         */
        if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
        {
            PQfinish(n_conn);
            password = prompt_for_password(user);
            continue;
        }

        /*
         * Failed to connect to the database. In interactive mode, keep the
         * previous connection to the DB; in scripting mode, close our
         * previous connection as well.
         */
        if (pset.cur_cmd_interactive)
        {
            psql_error("%s", PQerrorMessage(n_conn));

            /* pset.db is left unmodified */
            if (o_conn)
                psql_error("Previous connection kept\n");
        }
        else
        {
            psql_error("\\connect: %s", PQerrorMessage(n_conn));
            if (o_conn)
            {
                PQfinish(o_conn);
                pset.db = NULL;
            }
        }

        PQfinish(n_conn);
        return false;
    }

    /*
     * Replace the old connection with the new one, and update
     * connection-dependent variables.
     */
    PQsetNoticeProcessor(n_conn, NoticeProcessor, NULL);
    pset.db = n_conn;
    SyncVariables();
    connection_warnings(false); /* Must be after SyncVariables */

    /* Tell the user about the new connection */
    if (!pset.quiet)
    {
        if (param_is_newly_set(PQhost(o_conn), PQhost(pset.db)) ||
            param_is_newly_set(PQport(o_conn), PQport(pset.db)))
        {
            char       *host = PQhost(pset.db);

            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 now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
                       PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
            else
                printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
                       PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
        }
        else
            printf(_("You are now connected to database \"%s\" as user \"%s\".\n"),
                   PQdb(pset.db), PQuser(pset.db));
    }

    if (o_conn)
        PQfinish(o_conn);
    return true;
}

static bool do_edit ( const char *  filename_arg,
PQExpBuffer  query_buf,
int  lineno,
bool edited 
) [static]

Definition at line 1956 of file command.c.

References appendPQExpBufferChar(), appendPQExpBufferStr(), PQExpBufferData::data, editFile(), error(), PQExpBufferData::len, MAXPGPATH, NULL, PG_BINARY_R, psql_error(), resetPQExpBuffer(), snprintf(), and strerror().

Referenced by exec_command().

{
    char        fnametmp[MAXPGPATH];
    FILE       *stream = NULL;
    const char *fname;
    bool        error = false;
    int         fd;

    struct stat before,
                after;

    if (filename_arg)
        fname = filename_arg;
    else
    {
        /* make a temp file to edit */
#ifndef WIN32
        const char *tmpdir = getenv("TMPDIR");

        if (!tmpdir)
            tmpdir = "/tmp";
#else
        char        tmpdir[MAXPGPATH];
        int         ret;

        ret = GetTempPath(MAXPGPATH, tmpdir);
        if (ret == 0 || ret > MAXPGPATH)
        {
            psql_error("could not locate temporary directory: %s\n",
                       !ret ? strerror(errno) : "");
            return false;
        }

        /*
         * No canonicalize_path() here. EDIT.EXE run from CMD.EXE prepends the
         * current directory to the supplied path unless we use only
         * backslashes, so we do that.
         */
#endif
#ifndef WIN32
        snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
                 "/", (int) getpid());
#else
        snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
               "" /* trailing separator already present */ , (int) getpid());
#endif

        fname = (const char *) fnametmp;

        fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
        if (fd != -1)
            stream = fdopen(fd, "w");

        if (fd == -1 || !stream)
        {
            psql_error("could not open temporary file \"%s\": %s\n", fname, strerror(errno));
            error = true;
        }
        else
        {
            unsigned int ql = query_buf->len;

            if (ql == 0 || query_buf->data[ql - 1] != '\n')
            {
                appendPQExpBufferChar(query_buf, '\n');
                ql++;
            }

            if (fwrite(query_buf->data, 1, ql, stream) != ql)
            {
                psql_error("%s: %s\n", fname, strerror(errno));
                fclose(stream);
                remove(fname);
                error = true;
            }
            else if (fclose(stream) != 0)
            {
                psql_error("%s: %s\n", fname, strerror(errno));
                remove(fname);
                error = true;
            }
        }
    }

    if (!error && stat(fname, &before) != 0)
    {
        psql_error("%s: %s\n", fname, strerror(errno));
        error = true;
    }

    /* call editor */
    if (!error)
        error = !editFile(fname, lineno);

    if (!error && stat(fname, &after) != 0)
    {
        psql_error("%s: %s\n", fname, strerror(errno));
        error = true;
    }

    if (!error && before.st_mtime != after.st_mtime)
    {
        stream = fopen(fname, PG_BINARY_R);
        if (!stream)
        {
            psql_error("%s: %s\n", fname, strerror(errno));
            error = true;
        }
        else
        {
            /* read file back into query_buf */
            char        line[1024];

            resetPQExpBuffer(query_buf);
            while (fgets(line, sizeof(line), stream) != NULL)
                appendPQExpBufferStr(query_buf, line);

            if (ferror(stream))
            {
                psql_error("%s: %s\n", fname, strerror(errno));
                error = true;
            }
            else if (edited)
            {
                *edited = true;
            }

            fclose(stream);
        }
    }

    /* remove temp file */
    if (!filename_arg)
    {
        if (remove(fname) == -1)
        {
            psql_error("%s: %s\n", fname, strerror(errno));
            error = true;
        }
    }

    return !error;
}

bool do_pset ( const char *  param,
const char *  value,
printQueryOpt popt,
bool  quiet 
)

Definition at line 2244 of file command.c.

References _, _align2string(), Assert, printTableOpt::border, printTableOpt::columns, printTableOpt::default_footer, printTableOpt::expanded, printTableOpt::fieldSep, printTableOpt::format, free, get_line_style(), printTableOpt::line_style, printTextFormat::name, NULL, printQueryOpt::nullPrint, printTableOpt::numericLocale, printTableOpt::pager, ParseVariableBool(), pg_asciiformat, pg_asciiformat_old, pg_strcasecmp(), pg_strdup(), pg_strncasecmp(), pg_utf8format, psql_error(), printTableOpt::recordSep, separator::separator, separator::separator_zero, printTableOpt::tableAttr, printQueryOpt::title, printQueryOpt::topt, and printTableOpt::tuples_only.

Referenced by exec_command(), and parse_psql_options().

{
    size_t      vallen = 0;

    Assert(param != NULL);

    if (value)
        vallen = strlen(value);

    /* set format */
    if (strcmp(param, "format") == 0)
    {
        if (!value)
            ;
        else if (pg_strncasecmp("unaligned", value, vallen) == 0)
            popt->topt.format = PRINT_UNALIGNED;
        else if (pg_strncasecmp("aligned", value, vallen) == 0)
            popt->topt.format = PRINT_ALIGNED;
        else if (pg_strncasecmp("wrapped", value, vallen) == 0)
            popt->topt.format = PRINT_WRAPPED;
        else if (pg_strncasecmp("html", value, vallen) == 0)
            popt->topt.format = PRINT_HTML;
        else if (pg_strncasecmp("latex", value, vallen) == 0)
            popt->topt.format = PRINT_LATEX;
        else if (pg_strncasecmp("latex-longtable", value, vallen) == 0)
            popt->topt.format = PRINT_LATEX_LONGTABLE;
        else if (pg_strncasecmp("troff-ms", value, vallen) == 0)
            popt->topt.format = PRINT_TROFF_MS;
        else
        {
            psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, latex, troff-ms\n");
            return false;
        }

        if (!quiet)
            printf(_("Output format is %s.\n"), _align2string(popt->topt.format));
    }

    /* set table line style */
    else if (strcmp(param, "linestyle") == 0)
    {
        if (!value)
            ;
        else if (pg_strncasecmp("ascii", value, vallen) == 0)
            popt->topt.line_style = &pg_asciiformat;
        else if (pg_strncasecmp("old-ascii", value, vallen) == 0)
            popt->topt.line_style = &pg_asciiformat_old;
        else if (pg_strncasecmp("unicode", value, vallen) == 0)
            popt->topt.line_style = &pg_utf8format;
        else
        {
            psql_error("\\pset: allowed line styles are ascii, old-ascii, unicode\n");
            return false;
        }

        if (!quiet)
            printf(_("Line style is %s.\n"),
                   get_line_style(&popt->topt)->name);
    }

    /* set border style/width */
    else if (strcmp(param, "border") == 0)
    {
        if (value)
            popt->topt.border = atoi(value);

        if (!quiet)
            printf(_("Border style is %d.\n"), popt->topt.border);
    }

    /* set expanded/vertical mode */
    else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
    {
        if (value && pg_strcasecmp(value, "auto") == 0)
            popt->topt.expanded = 2;
        else if (value)
            popt->topt.expanded = ParseVariableBool(value);
        else
            popt->topt.expanded = !popt->topt.expanded;
        if (!quiet)
        {
            if (popt->topt.expanded == 1)
                printf(_("Expanded display is on.\n"));
            else if (popt->topt.expanded == 2)
                printf(_("Expanded display is used automatically.\n"));
            else
                printf(_("Expanded display is off.\n"));
        }
    }

    /* locale-aware numeric output */
    else if (strcmp(param, "numericlocale") == 0)
    {
        if (value)
            popt->topt.numericLocale = ParseVariableBool(value);
        else
            popt->topt.numericLocale = !popt->topt.numericLocale;
        if (!quiet)
        {
            if (popt->topt.numericLocale)
                puts(_("Showing locale-adjusted numeric output."));
            else
                puts(_("Locale-adjusted numeric output is off."));
        }
    }

    /* null display */
    else if (strcmp(param, "null") == 0)
    {
        if (value)
        {
            free(popt->nullPrint);
            popt->nullPrint = pg_strdup(value);
        }
        if (!quiet)
            printf(_("Null display is \"%s\".\n"), popt->nullPrint ? popt->nullPrint : "");
    }

    /* field separator for unaligned text */
    else if (strcmp(param, "fieldsep") == 0)
    {
        if (value)
        {
            free(popt->topt.fieldSep.separator);
            popt->topt.fieldSep.separator = pg_strdup(value);
            popt->topt.fieldSep.separator_zero = false;
        }
        if (!quiet)
        {
            if (popt->topt.fieldSep.separator_zero)
                printf(_("Field separator is zero byte.\n"));
            else
                printf(_("Field separator is \"%s\".\n"), popt->topt.fieldSep.separator);
        }
    }

    else if (strcmp(param, "fieldsep_zero") == 0)
    {
        free(popt->topt.fieldSep.separator);
        popt->topt.fieldSep.separator = NULL;
        popt->topt.fieldSep.separator_zero = true;
        if (!quiet)
            printf(_("Field separator is zero byte.\n"));
    }

    /* record separator for unaligned text */
    else if (strcmp(param, "recordsep") == 0)
    {
        if (value)
        {
            free(popt->topt.recordSep.separator);
            popt->topt.recordSep.separator = pg_strdup(value);
            popt->topt.recordSep.separator_zero = false;
        }
        if (!quiet)
        {
            if (popt->topt.recordSep.separator_zero)
                printf(_("Record separator is zero byte.\n"));
            else if (strcmp(popt->topt.recordSep.separator, "\n") == 0)
                printf(_("Record separator is <newline>."));
            else
                printf(_("Record separator is \"%s\".\n"), popt->topt.recordSep.separator);
        }
    }

    else if (strcmp(param, "recordsep_zero") == 0)
    {
        free(popt->topt.recordSep.separator);
        popt->topt.recordSep.separator = NULL;
        popt->topt.recordSep.separator_zero = true;
        if (!quiet)
            printf(_("Record separator is zero byte.\n"));
    }

    /* toggle between full and tuples-only format */
    else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
    {
        if (value)
            popt->topt.tuples_only = ParseVariableBool(value);
        else
            popt->topt.tuples_only = !popt->topt.tuples_only;
        if (!quiet)
        {
            if (popt->topt.tuples_only)
                puts(_("Showing only tuples."));
            else
                puts(_("Tuples only is off."));
        }
    }

    /* set title override */
    else if (strcmp(param, "title") == 0)
    {
        free(popt->title);
        if (!value)
            popt->title = NULL;
        else
            popt->title = pg_strdup(value);

        if (!quiet)
        {
            if (popt->title)
                printf(_("Title is \"%s\".\n"), popt->title);
            else
                printf(_("Title is unset.\n"));
        }
    }

    /* set HTML table tag options */
    else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
    {
        free(popt->topt.tableAttr);
        if (!value)
            popt->topt.tableAttr = NULL;
        else
            popt->topt.tableAttr = pg_strdup(value);

        if (!quiet)
        {
            if (popt->topt.tableAttr)
                printf(_("Table attribute is \"%s\".\n"), popt->topt.tableAttr);
            else
                printf(_("Table attributes unset.\n"));
        }
    }

    /* toggle use of pager */
    else if (strcmp(param, "pager") == 0)
    {
        if (value && pg_strcasecmp(value, "always") == 0)
            popt->topt.pager = 2;
        else if (value)
            if (ParseVariableBool(value))
                popt->topt.pager = 1;
            else
                popt->topt.pager = 0;
        else if (popt->topt.pager == 1)
            popt->topt.pager = 0;
        else
            popt->topt.pager = 1;
        if (!quiet)
        {
            if (popt->topt.pager == 1)
                puts(_("Pager is used for long output."));
            else if (popt->topt.pager == 2)
                puts(_("Pager is always used."));
            else
                puts(_("Pager usage is off."));
        }
    }

    /* disable "(x rows)" footer */
    else if (strcmp(param, "footer") == 0)
    {
        if (value)
            popt->topt.default_footer = ParseVariableBool(value);
        else
            popt->topt.default_footer = !popt->topt.default_footer;
        if (!quiet)
        {
            if (popt->topt.default_footer)
                puts(_("Default footer is on."));
            else
                puts(_("Default footer is off."));
        }
    }

    /* set border style/width */
    else if (strcmp(param, "columns") == 0)
    {
        if (value)
            popt->topt.columns = atoi(value);

        if (!quiet)
            printf(_("Target width is %d.\n"), popt->topt.columns);
    }

    else
    {
        psql_error("\\pset: unknown option: %s\n", param);
        return false;
    }

    return true;
}

static bool do_shell ( const char *  command  )  [static]

Definition at line 2543 of file command.c.

References free, NULL, pg_malloc(), psql_error(), system(), and SYSTEMQUOTE.

Referenced by exec_command().

{
    int         result;

    if (!command)
    {
        char       *sys;
        const char *shellName;

        shellName = getenv("SHELL");
#ifdef WIN32
        if (shellName == NULL)
            shellName = getenv("COMSPEC");
#endif
        if (shellName == NULL)
            shellName = DEFAULT_SHELL;

        sys = pg_malloc(strlen(shellName) + 16);
#ifndef WIN32
        sprintf(sys,
        /* See EDITOR handling comment for an explanation */
                "exec %s", shellName);
#else
        /* See EDITOR handling comment for an explanation */
        sprintf(sys, SYSTEMQUOTE "\"%s\"" SYSTEMQUOTE, shellName);
#endif
        result = system(sys);
        free(sys);
    }
    else
        result = system(command);

    if (result == 127 || result == -1)
    {
        psql_error("\\!: failed\n");
        return false;
    }
    return true;
}

static bool do_watch ( PQExpBuffer  query_buf,
long  sleep 
) [static]

Definition at line 2590 of file command.c.

References _, cancel_pressed, PQExpBufferData::data, i, PQExpBufferData::len, _psqlSettings::logfile, NULL, printQueryOpt::nullPrint, printTableOpt::pager, pg_usleep(), PGRES_EMPTY_QUERY, PGRES_TUPLES_OK, _psqlSettings::popt, PQclear(), PQresultStatus(), printQuery(), pset, psql_error(), PSQLexec(), _psqlSettings::queryFout, sigint_interrupt_enabled, sigint_interrupt_jmp, sigsetjmp, snprintf(), printQueryOpt::title, and printQueryOpt::topt.

Referenced by exec_command().

{
    printQueryOpt myopt = pset.popt;
    char        title[50];

    if (!query_buf || query_buf->len <= 0)
    {
        psql_error(_("\\watch cannot be used with an empty query\n"));
        return false;
    }

    /*
     * Set up rendering options, in particular, disable the pager, because
     * nobody wants to be prompted while watching the output of 'watch'.
     */
    myopt.nullPrint = NULL;
    myopt.topt.pager = 0;

    for (;;)
    {
        PGresult   *res;
        time_t      timer;
        long        i;

        /*
         * Prepare title for output.  XXX would it be better to use the time
         * of completion of the command?
         */
        timer = time(NULL);
        snprintf(title, sizeof(title), _("Watch every %lds\t%s"),
                 sleep, asctime(localtime(&timer)));
        myopt.title = title;

        /*
         * Run the query.  We use PSQLexec, which is kind of cheating, but
         * SendQuery doesn't let us suppress autocommit behavior.
         */
        res = PSQLexec(query_buf->data, false);

        /* PSQLexec handles failure results and returns NULL */
        if (res == NULL)
            break;

        /*
         * If SIGINT is sent while the query is processing, PSQLexec will
         * consume the interrupt.  The user's intention, though, is to cancel
         * the entire watch process, so detect a sent cancellation request and
         * exit in this case.
         */
        if (cancel_pressed)
        {
            PQclear(res);
            break;
        }

        switch (PQresultStatus(res))
        {
            case PGRES_TUPLES_OK:
                printQuery(res, &myopt, pset.queryFout, pset.logfile);
                break;

            case PGRES_EMPTY_QUERY:
                psql_error(_("\\watch cannot be used with an empty query\n"));
                PQclear(res);
                return false;

            default:
                /* should we fail for non-tuple-result commands? */
                break;
        }

        PQclear(res);

        /*
         * Set up cancellation of 'watch' via SIGINT.  We redo this each time
         * through the loop since it's conceivable something inside PSQLexec
         * could change sigint_interrupt_jmp.
         */
        if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
            break;

        /*
         * Enable 'watch' cancellations and wait a while before running the
         * query again.  Break the sleep into short intervals since pg_usleep
         * isn't interruptible on some platforms.
         */
        sigint_interrupt_enabled = true;
        for (i = 0; i < sleep; i++)
        {
            pg_usleep(1000000L);
            if (cancel_pressed)
                break;
        }
        sigint_interrupt_enabled = false;
    }

    return true;
}

static bool editFile ( const char *  fname,
int  lineno 
) [static]

Definition at line 1880 of file command.c.

References Assert, free, NULL, pg_malloc(), psql_error(), system(), and SYSTEMQUOTE.

Referenced by do_edit().

{
    const char *editorName;
    const char *editor_lineno_arg = NULL;
    char       *sys;
    int         result;

    Assert(fname != NULL);

    /* Find an editor to use */
    editorName = getenv("PSQL_EDITOR");
    if (!editorName)
        editorName = getenv("EDITOR");
    if (!editorName)
        editorName = getenv("VISUAL");
    if (!editorName)
        editorName = DEFAULT_EDITOR;

    /* Get line number argument, if we need it. */
    if (lineno > 0)
    {
        editor_lineno_arg = getenv("PSQL_EDITOR_LINENUMBER_ARG");
#ifdef DEFAULT_EDITOR_LINENUMBER_ARG
        if (!editor_lineno_arg)
            editor_lineno_arg = DEFAULT_EDITOR_LINENUMBER_ARG;
#endif
        if (!editor_lineno_arg)
        {
            psql_error("environment variable PSQL_EDITOR_LINENUMBER_ARG must be set to specify a line number\n");
            return false;
        }
    }

    /* Allocate sufficient memory for command line. */
    if (lineno > 0)
        sys = pg_malloc(strlen(editorName)
                        + strlen(editor_lineno_arg) + 10        /* for integer */
                        + 1 + strlen(fname) + 10 + 1);
    else
        sys = pg_malloc(strlen(editorName) + strlen(fname) + 10 + 1);

    /*
     * On Unix the EDITOR value should *not* be quoted, since it might include
     * switches, eg, EDITOR="pico -t"; it's up to the user to put quotes in it
     * if necessary.  But this policy is not very workable on Windows, due to
     * severe brain damage in their command shell plus the fact that standard
     * program paths include spaces.
     */
#ifndef WIN32
    if (lineno > 0)
        sprintf(sys, "exec %s %s%d '%s'",
                editorName, editor_lineno_arg, lineno, fname);
    else
        sprintf(sys, "exec %s '%s'",
                editorName, fname);
#else
    if (lineno > 0)
        sprintf(sys, SYSTEMQUOTE "\"%s\" %s%d \"%s\"" SYSTEMQUOTE,
                editorName, editor_lineno_arg, lineno, fname);
    else
        sprintf(sys, SYSTEMQUOTE "\"%s\" \"%s\"" SYSTEMQUOTE,
                editorName, fname);
#endif
    result = system(sys);
    if (result == -1)
        psql_error("could not start editor \"%s\"\n", editorName);
    else if (result == 127)
        psql_error("could not start /bin/sh\n");
    free(sys);

    return result == 0;
}

static backslashResult exec_command ( const char *  cmd,
PsqlScanState  scan_state,
PQExpBuffer  query_buf 
) [static]

Definition at line 188 of file command.c.

References _, appendStringLiteralConn(), buf, canonicalize_path(), ClosePager(), createPQExpBuffer(), PQExpBufferData::data, _psqlSettings::db, describeAggregates(), describeFunctions(), describeOperators(), describeRoles(), describeTableDetails(), describeTablespaces(), describeTypes(), destroyPQExpBuffer(), DEVTTY, _psqlSettings::dirname, do_connect(), do_copy(), do_edit(), do_lo_export(), do_lo_import(), do_lo_list(), do_lo_unlink(), do_pset(), do_shell(), do_watch(), printTableOpt::encoding, _psqlSettings::encoding, encoding, EXIT_FAILURE, expand_tilde(), fd(), fmtId(), printTableOpt::format, free, get_create_function_cmd(), gets_fromFile(), gettext, _psqlSettings::gfname, _psqlSettings::gset_prefix, helpSQL(), i, initPQExpBuffer(), _psqlSettings::inputfile, is_absolute_path, PQExpBufferData::len, listAllDbs(), listCasts(), listCollations(), listConversions(), listDbRoleSettings(), listDefaultACLs(), listDomains(), listEventTriggers(), listExtensionContents(), listExtensions(), listForeignDataWrappers(), listForeignServers(), listForeignTables(), listLanguages(), listSchemas(), listTables(), listTSConfigs(), listTSDictionaries(), listTSParsers(), listTSTemplates(), listUserMappings(), lookup_function_oid(), NULL, objectDescription(), OT_FILEPIPE, OT_NORMAL, OT_SQLID, OT_WHOLE_LINE, PageOutput(), printTableOpt::pager, ParseVariableBool(), permissionsList(), pg_encoding_to_char(), pg_malloc(), pg_strcasecmp(), pg_strdup(), _psqlSettings::popt, PQclear(), PQclientEncoding(), PQdb(), PQencryptPassword(), PQfreemem(), PQhost(), PQport(), PQsetClientEncoding(), PQuser(), PRINT_ALIGNED, print_copyright(), PRINT_HTML, printfPQExpBuffer(), printSSLInfo(), PrintVariables(), process_file(), pset, PSQL_CMD_ERROR, psql_error(), psql_scan_reset(), psql_scan_slash_option(), PSQLexec(), putenv, _psqlSettings::queryFout, _psqlSettings::quiet, read_connect_arg(), realloc, resetPQExpBuffer(), saveHistory(), setQFout(), SetVariable(), simple_prompt(), slashUsage(), snprintf(), status(), strerror(), strip_lineno_from_funcdesc(), _psqlSettings::sversion, termPQExpBuffer(), _psqlSettings::timing, printQueryOpt::topt, unsetenv, user, value, and _psqlSettings::vars.

Referenced by HandleSlashCmds().

{
    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 currently not connected to a database.\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));
            printSSLInfo();
        }
    }

    /* \copy */
    else if (pg_strcasecmp(cmd, "copy") == 0)
    {
        char       *opt = psql_scan_slash_option(scan_state,
                                                 OT_WHOLE_LINE, NULL, false);

        success = do_copy(opt);
        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':
                if (pattern)
                    success = describeTableDetails(pattern, show_verbose, show_system);
                else
                    /* standard listing of interesting things */
                    success = listTables("tvmsE", 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_verbose, show_system);
                break;
            case 'C':
                success = listCasts(pattern, show_verbose);
                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_verbose, 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 'L':
                success = listLanguages(pattern, show_verbose, show_system);
                break;
            case 'n':
                success = listSchemas(pattern, show_verbose, show_system);
                break;
            case 'o':
                success = describeOperators(pattern, show_system);
                break;
            case 'O':
                success = listCollations(pattern, show_verbose, show_system);
                break;
            case 'p':
                success = permissionsList(pattern);
                break;
            case 'T':
                success = describeTypes(pattern, show_verbose, show_system);
                break;
            case 't':
            case 'v':
            case 'm':
            case 'i':
            case 's':
            case 'E':
                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;
                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 'e':           /* SQL/MED subsystem */
                switch (cmd[2])
                {
                    case 's':
                        success = listForeignServers(pattern, show_verbose);
                        break;
                    case 'u':
                        success = listUserMappings(pattern, show_verbose);
                        break;
                    case 'w':
                        success = listForeignDataWrappers(pattern, show_verbose);
                        break;
                    case 't':
                        success = listForeignTables(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;
            case 'y':           /* Event Triggers */
                success = listEventTriggers(pattern, show_verbose);
                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;
            char       *ln = NULL;
            int         lineno = -1;

            fname = psql_scan_slash_option(scan_state,
                                           OT_NORMAL, NULL, true);
            if (fname)
            {
                /* try to get separate lineno arg */
                ln = psql_scan_slash_option(scan_state,
                                            OT_NORMAL, NULL, true);
                if (ln == NULL)
                {
                    /* only one arg; maybe it is lineno not fname */
                    if (fname[0] &&
                        strspn(fname, "0123456789") == strlen(fname))
                    {
                        /* all digits, so assume it is lineno */
                        ln = fname;
                        fname = NULL;
                    }
                }
            }
            if (ln)
            {
                lineno = atoi(ln);
                if (lineno < 1)
                {
                    psql_error("invalid line number: %s\n", ln);
                    status = PSQL_CMD_ERROR;
                }
            }
            if (status != PSQL_CMD_ERROR)
            {
                expand_tilde(&fname);
                if (fname)
                    canonicalize_path(fname);
                if (do_edit(fname, query_buf, lineno, NULL))
                    status = PSQL_CMD_NEWEDIT;
                else
                    status = PSQL_CMD_ERROR;
            }
            if (fname)
                free(fname);
            if (ln)
                free(ln);
        }
    }

    /*
     * \ef -- edit the named function, or present a blank CREATE FUNCTION
     * template if no argument is given
     */
    else if (strcmp(cmd, "ef") == 0)
    {
        int         lineno = -1;

        if (pset.sversion < 80400)
        {
            psql_error("The server (version %d.%d) does not support editing function source.\n",
                       pset.sversion / 10000, (pset.sversion / 100) % 100);
            status = PSQL_CMD_ERROR;
        }
        else 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);
            lineno = strip_lineno_from_funcdesc(func);
            if (lineno == 0)
            {
                /* error already reported */
                status = PSQL_CMD_ERROR;
            }
            else 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;
            }
            else if (lineno > 0)
            {
                /*
                 * lineno "1" should correspond to the first line of the
                 * function body.  We expect that pg_get_functiondef() will
                 * emit that on a line beginning with "AS ", and that there
                 * can be no such line before the real start of the function
                 * body.  Increment lineno by the number of lines before that
                 * line, so that it becomes relative to the first line of the
                 * function definition.
                 */
                const char *lines = query_buf->data;

                while (*lines != '\0')
                {
                    if (strncmp(lines, "AS ", 3) == 0)
                        break;
                    lineno++;
                    /* find start of next line */
                    lines = strchr(lines, '\n');
                    if (!lines)
                        break;
                    lines++;
                }
            }

            if (func)
                free(func);
        }

        if (status != PSQL_CMD_ERROR)
        {
            bool        edited = false;

            if (!do_edit(NULL, query_buf, lineno, &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, &quoted, 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 [filename] -- send query, optionally with output to file/pipe */
    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;
    }

    /* \gset [prefix] -- send query and store result into variables */
    else if (strcmp(cmd, "gset") == 0)
    {
        char       *prefix = psql_scan_slash_option(scan_state,
                                                    OT_NORMAL, NULL, false);

        if (prefix)
            pset.gset_prefix = prefix;
        else
        {
            /* we must set a non-NULL prefix to trigger storing */
            pset.gset_prefix = pg_strdup("");
        }
        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 and \ir include files */
    else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0
           || strcmp(cmd, "ir") == 0 || strcmp(cmd, "include_relative") == 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
        {
            bool        include_relative;

            include_relative = (strcmp(cmd, "ir") == 0
                                || strcmp(cmd, "include_relative") == 0);
            expand_tilde(&fname);
            success = (process_file(fname, false, include_relative) == EXIT_SUCCESS);
            free(fname);
        }
    }

    /* \l is list databases */
    else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0 ||
             strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
    {
        char       *pattern;
        bool        show_verbose;

        pattern = psql_scan_slash_option(scan_state,
                                         OT_NORMAL, NULL, true);

        show_verbose = strchr(cmd, '+') ? true : false;

        success = listAllDbs(pattern, show_verbose);

        if (pattern)
            free(pattern);
    }

    /*
     * 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: ", 100, false);
        pw2 = simple_prompt("Enter it again: ", 100, false);

        if (strcmp(pw1, pw2) != 0)
        {
            psql_error("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)
            {
                psql_error("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);
            }

            if (opt0)
                free(opt0);
        }

        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 while setting variable\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 while setting variable\n", cmd);
                success = false;
            }
            free(newval);
        }
        free(opt0);
    }


    /* \setenv -- set environment command */
    else if (strcmp(cmd, "setenv") == 0)
    {
        char       *envvar = psql_scan_slash_option(scan_state,
                                                    OT_NORMAL, NULL, false);
        char       *envval = psql_scan_slash_option(scan_state,
                                                    OT_NORMAL, NULL, false);

        if (!envvar)
        {
            psql_error("\\%s: missing required argument\n", cmd);
            success = false;
        }
        else if (strchr(envvar, '=') != NULL)
        {
            psql_error("\\%s: environment variable name must not contain \"=\"\n",
                       cmd);
            success = false;
        }
        else if (!envval)
        {
            /* No argument - unset the environment variable */
            unsetenv(envvar);
            success = true;
        }
        else
        {
            /* Set variable to the value of the next argument */
            int         len = strlen(envvar) + strlen(envval) + 1;
            char       *newval = pg_malloc(len + 1);

            snprintf(newval, len + 1, "%s=%s", envvar, envval);
            putenv(newval);
            success = true;

            /*
             * Do not free newval here, it will screw up the environment if
             * you do. See putenv man page for details. That means we leak a
             * bit of memory here, but not enough to worry about.
             */
        }
        free(envvar);
        free(envval);
    }

    /* \sf -- show a function's source code */
    else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
    {
        bool        show_linenumbers = (strcmp(cmd, "sf+") == 0);
        PQExpBuffer func_buf;
        char       *func;
        Oid         foid = InvalidOid;

        func_buf = createPQExpBuffer();
        func = psql_scan_slash_option(scan_state,
                                      OT_WHOLE_LINE, NULL, true);
        if (pset.sversion < 80400)
        {
            psql_error("The server (version %d.%d) does not support showing function source.\n",
                       pset.sversion / 10000, (pset.sversion / 100) % 100);
            status = PSQL_CMD_ERROR;
        }
        else if (!func)
        {
            psql_error("function name is required\n");
            status = PSQL_CMD_ERROR;
        }
        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, func_buf))
        {
            /* error already reported */
            status = PSQL_CMD_ERROR;
        }
        else
        {
            FILE       *output;
            bool        is_pager;

            /* Select output stream: stdout, pager, or file */
            if (pset.queryFout == stdout)
            {
                /* count lines in function to see if pager is needed */
                int         lineno = 0;
                const char *lines = func_buf->data;

                while (*lines != '\0')
                {
                    lineno++;
                    /* find start of next line */
                    lines = strchr(lines, '\n');
                    if (!lines)
                        break;
                    lines++;
                }

                output = PageOutput(lineno, pset.popt.topt.pager);
                is_pager = true;
            }
            else
            {
                /* use previously set output file, without pager */
                output = pset.queryFout;
                is_pager = false;
            }

            if (show_linenumbers)
            {
                bool        in_header = true;
                int         lineno = 0;
                char       *lines = func_buf->data;

                /*
                 * lineno "1" should correspond to the first line of the
                 * function body.  We expect that pg_get_functiondef() will
                 * emit that on a line beginning with "AS ", and that there
                 * can be no such line before the real start of the function
                 * body.
                 *
                 * Note that this loop scribbles on func_buf.
                 */
                while (*lines != '\0')
                {
                    char       *eol;

                    if (in_header && strncmp(lines, "AS ", 3) == 0)
                        in_header = false;
                    /* increment lineno only for body's lines */
                    if (!in_header)
                        lineno++;

                    /* find and mark end of current line */
                    eol = strchr(lines, '\n');
                    if (eol != NULL)
                        *eol = '\0';

                    /* show current line as appropriate */
                    if (in_header)
                        fprintf(output, "        %s\n", lines);
                    else
                        fprintf(output, "%-7d %s\n", lineno, lines);

                    /* advance to next line, if any */
                    if (eol == NULL)
                        break;
                    lines = ++eol;
                }
            }
            else
            {
                /* just send the function definition to output */
                fputs(func_buf->data, output);
            }

            if (is_pager)
                ClosePager(output);
        }

        if (func)
            free(func);
        destroyPQExpBuffer(func_buf);
    }

    /* \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 while setting variable\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);
    }

    /* \watch -- execute a query every N seconds */
    else if (strcmp(cmd, "watch") == 0)
    {
        char       *opt = psql_scan_slash_option(scan_state,
                                                 OT_NORMAL, NULL, true);
        long        sleep = 2;

        /* Convert optional sleep-length argument */
        if (opt)
        {
            sleep = strtol(opt, NULL, 10);
            if (sleep <= 0)
                sleep = 1;
            free(opt);
        }

        success = do_watch(query_buf, sleep);

        /* Reset the query buffer as though for \r */
        resetPQExpBuffer(query_buf);
        psql_scan_reset(scan_state);
    }

    /* \x -- set or 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)))
        {
            psql_error("+ opt(%d) = |%s|\n", i++, value);
            free(value);
        }
    }
#endif

    else
        status = PSQL_CMD_UNKNOWN;

    if (!success)
        status = PSQL_CMD_ERROR;

    return status;
}

static bool get_create_function_cmd ( PGconn conn,
Oid  oid,
PQExpBuffer  buf 
) [static]

Definition at line 2731 of file command.c.

References appendPQExpBufferStr(), createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), minimal_error_message(), PGRES_TUPLES_OK, PQclear(), PQexec(), PQgetvalue(), PQntuples(), PQresultStatus(), printfPQExpBuffer(), and resetPQExpBuffer().

Referenced by exec_command().

{
    bool        result = true;
    PQExpBuffer query;
    PGresult   *res;

    query = createPQExpBuffer();
    printfPQExpBuffer(query, "SELECT pg_catalog.pg_get_functiondef(%u)", oid);

    res = PQexec(conn, query->data);
    if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
    {
        resetPQExpBuffer(buf);
        appendPQExpBufferStr(buf, PQgetvalue(res, 0, 0));
    }
    else
    {
        minimal_error_message(res);
        result = false;
    }

    PQclear(res);
    destroyPQExpBuffer(query);

    return result;
}

backslashResult HandleSlashCmds ( PsqlScanState  scan_state,
PQExpBuffer  query_buf 
)

Definition at line 97 of file command.c.

References arg, Assert, _psqlSettings::cur_cmd_interactive, exec_command(), free, NULL, OT_NO_EVAL, OT_WHOLE_LINE, pset, PSQL_CMD_ERROR, PSQL_CMD_UNKNOWN, psql_error(), psql_scan_slash_command(), psql_scan_slash_command_end(), psql_scan_slash_option(), _psqlSettings::queryFout, and status().

Referenced by main(), and MainLoop().

{
    backslashResult status = PSQL_CMD_SKIP_LINE;
    char       *cmd;
    char       *arg;

    Assert(scan_state != NULL);

    /* Parse off the command name */
    cmd = psql_scan_slash_command(scan_state);

    /* And try to execute it */
    status = exec_command(cmd, scan_state, query_buf);

    if (status == PSQL_CMD_UNKNOWN)
    {
        if (pset.cur_cmd_interactive)
            psql_error("Invalid command \\%s. Try \\? for help.\n", cmd);
        else
            psql_error("invalid command \\%s\n", cmd);
        status = PSQL_CMD_ERROR;
    }

    if (status != PSQL_CMD_ERROR)
    {
        /* eat any remaining arguments after a valid command */
        /* note we suppress evaluation of backticks here */
        while ((arg = psql_scan_slash_option(scan_state,
                                             OT_NO_EVAL, NULL, false)))
        {
            psql_error("\\%s: extra argument \"%s\" ignored\n", cmd, arg);
            free(arg);
        }
    }
    else
    {
        /* silently throw away rest of line after an erroneous command */
        while ((arg = psql_scan_slash_option(scan_state,
                                             OT_WHOLE_LINE, NULL, false)))
            free(arg);
    }

    /* if there is a trailing \\, swallow it */
    psql_scan_slash_command_end(scan_state);

    free(cmd);

    /* some commands write to queryFout, so make sure output is sent */
    fflush(pset.queryFout);

    return status;
}

static bool lookup_function_oid ( PGconn conn,
const char *  desc,
Oid foid 
) [static]

Definition at line 2699 of file command.c.

References appendPQExpBuffer(), appendStringLiteralConn(), atooid, createPQExpBuffer(), PQExpBufferData::data, destroyPQExpBuffer(), minimal_error_message(), PGRES_TUPLES_OK, PQclear(), PQexec(), PQgetvalue(), PQntuples(), PQresultStatus(), and printfPQExpBuffer().

Referenced by exec_command().

{
    bool        result = true;
    PQExpBuffer query;
    PGresult   *res;

    query = createPQExpBuffer();
    printfPQExpBuffer(query, "SELECT ");
    appendStringLiteralConn(query, desc, conn);
    appendPQExpBuffer(query, "::pg_catalog.%s::pg_catalog.oid",
                      strchr(desc, '(') ? "regprocedure" : "regproc");

    res = PQexec(conn, query->data);
    if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
        *foid = atooid(PQgetvalue(res, 0, 0));
    else
    {
        minimal_error_message(res);
        result = false;
    }

    PQclear(res);
    destroyPQExpBuffer(query);

    return result;
}

static void minimal_error_message ( PGresult res  )  [static]
static bool param_is_newly_set ( const char *  old_val,
const char *  new_val 
) [static]

Definition at line 1551 of file command.c.

References NULL.

Referenced by do_connect().

{
    if (new_val == NULL)
        return false;

    if (old_val == NULL || strcmp(old_val, new_val) != 0)
        return true;

    return false;
}

static void printSSLInfo ( void   )  [static]

Definition at line 1782 of file command.c.

References _, _psqlSettings::db, PQgetssl(), and pset.

Referenced by connection_warnings(), and exec_command().

{
#ifdef USE_SSL
    int         sslbits = -1;
    SSL        *ssl;

    ssl = PQgetssl(pset.db);
    if (!ssl)
        return;                 /* no SSL */

    SSL_get_cipher_bits(ssl, &sslbits);
    printf(_("SSL connection (cipher: %s, bits: %d)\n"),
           SSL_get_cipher(ssl), sslbits);
#else

    /*
     * If psql is compiled without SSL but is using a libpq with SSL, we
     * cannot figure out the specifics about the connection. But we know it's
     * SSL secured.
     */
    if (PQgetssl(pset.db))
        printf(_("SSL connection (unknown cipher)\n"));
#endif
}

int process_file ( char *  filename,
bool  single_txn,
bool  use_relative_path 
)

Definition at line 2114 of file command.c.

References canonicalize_path(), error(), get_parent_directory(), has_drive_prefix(), _psqlSettings::inputfile, is_absolute_path, join_path_components(), MainLoop(), NULL, _psqlSettings::on_error_stop, PG_BINARY_R, PQclear(), pset, psql_error(), PSQLexec(), relpath, strerror(), and strlcpy().

{
    FILE       *fd;
    int         result;
    char       *oldfilename;
    char        relpath[MAXPGPATH];
    PGresult   *res;

    if (!filename)
    {
        fd = stdin;
        filename = NULL;
    }
    else if (strcmp(filename, "-") != 0)
    {
        canonicalize_path(filename);

        /*
         * If we were asked to resolve the pathname relative to the location
         * of the currently executing script, and there is one, and this is a
         * relative pathname, then prepend all but the last pathname component
         * of the current script to this pathname.
         */
        if (use_relative_path && pset.inputfile &&
            !is_absolute_path(filename) && !has_drive_prefix(filename))
        {
            strlcpy(relpath, pset.inputfile, sizeof(relpath));
            get_parent_directory(relpath);
            join_path_components(relpath, relpath, filename);
            canonicalize_path(relpath);

            filename = relpath;
        }

        fd = fopen(filename, PG_BINARY_R);

        if (!fd)
        {
            psql_error("%s: %s\n", filename, strerror(errno));
            return EXIT_FAILURE;
        }
    }
    else
    {
        fd = stdin;
        filename = "<stdin>";   /* for future error messages */
    }

    oldfilename = pset.inputfile;
    pset.inputfile = filename;

    if (single_txn)
    {
        if ((res = PSQLexec("BEGIN", false)) == NULL)
        {
            if (pset.on_error_stop)
            {
                result = EXIT_USER;
                goto error;
            }
        }
        else
            PQclear(res);
    }

    result = MainLoop(fd);

    if (single_txn)
    {
        if ((res = PSQLexec("COMMIT", false)) == NULL)
        {
            if (pset.on_error_stop)
            {
                result = EXIT_USER;
                goto error;
            }
        }
        else
            PQclear(res);
    }

error:
    if (fd != stdin)
        fclose(fd);

    pset.inputfile = oldfilename;
    return result;
}

static char* prompt_for_password ( const char *  username  )  [static]

Definition at line 1530 of file command.c.

References _, free, NULL, pg_malloc(), simple_prompt(), and snprintf().

Referenced by do_connect().

{
    char       *result;

    if (username == NULL)
        result = simple_prompt("Password: ", 100, false);
    else
    {
        char       *prompt_text;

        prompt_text = pg_malloc(strlen(username) + 100);
        snprintf(prompt_text, strlen(username) + 100,
                 _("Password for user %s: "), username);
        result = simple_prompt(prompt_text, 100, false);
        free(prompt_text);
    }

    return result;
}

static char* read_connect_arg ( PsqlScanState  scan_state  )  [static]

Definition at line 155 of file command.c.

References OT_SQLIDHACK, and psql_scan_slash_option().

Referenced by exec_command().

{
    char       *result;
    char        quote;

    /*
     * Ideally we should treat the arguments as SQL identifiers.  But for
     * backwards compatibility with 7.2 and older pg_dump files, we have to
     * take unquoted arguments verbatim (don't downcase them). For now,
     * double-quoted arguments may be stripped of double quotes (as if SQL
     * identifiers).  By 7.4 or so, pg_dump files can be expected to
     * double-quote all mixed-case \connect arguments, and then we can get rid
     * of OT_SQLIDHACK.
     */
    result = psql_scan_slash_option(scan_state, OT_SQLIDHACK, &quote, true);

    if (!result)
        return NULL;

    if (quote)
        return result;

    if (*result == '\0' || strcmp(result, "-") == 0)
        return NULL;

    return result;
}

static int strip_lineno_from_funcdesc ( char *  func  )  [static]

Definition at line 2768 of file command.c.

References isascii, and psql_error().

Referenced by exec_command().

{
    char       *c;
    int         lineno;

    if (!func || func[0] == '\0')
        return -1;

    c = func + strlen(func) - 1;

    /*
     * This business of parsing backwards is dangerous as can be in a
     * multibyte environment: there is no reason to believe that we are
     * looking at the first byte of a character, nor are we necessarily
     * working in a "safe" encoding.  Fortunately the bitpatterns we are
     * looking for are unlikely to occur as non-first bytes, but beware of
     * trying to expand the set of cases that can be recognized.  We must
     * guard the <ctype.h> macros by using isascii() first, too.
     */

    /* skip trailing whitespace */
    while (c > func && isascii((unsigned char) *c) && isspace((unsigned char) *c))
        c--;

    /* must have a digit as last non-space char */
    if (c == func || !isascii((unsigned char) *c) || !isdigit((unsigned char) *c))
        return -1;

    /* find start of digit string */
    while (c > func && isascii((unsigned char) *c) && isdigit((unsigned char) *c))
        c--;

    /* digits must be separated from func name by space or closing paren */
    /* notice also that we are not allowing an empty func name ... */
    if (c == func || !isascii((unsigned char) *c) ||
        !(isspace((unsigned char) *c) || *c == ')'))
        return -1;

    /* parse digit string */
    c++;
    lineno = atoi(c);
    if (lineno < 1)
    {
        psql_error("invalid line number: %s\n", c);
        return 0;
    }

    /* strip digit string from func */
    *c = '\0';

    return lineno;
}

void SyncVariables ( void   ) 
void UnsyncVariables ( void   ) 

Definition at line 1863 of file command.c.

References NULL, pset, SetVariable(), and _psqlSettings::vars.

Referenced by CheckConnection().

{
    SetVariable(pset.vars, "DBNAME", NULL);
    SetVariable(pset.vars, "USER", NULL);
    SetVariable(pset.vars, "HOST", NULL);
    SetVariable(pset.vars, "PORT", NULL);
    SetVariable(pset.vars, "ENCODING", NULL);
}