Commit 7c9390ca authored by Peter Eisentraut's avatar Peter Eisentraut

Fixed psql variables vs array syntax, as well as minor psql enhancements

parent 4ceb2d0c
This diff is collapsed.
This diff is collapsed.
......@@ -24,19 +24,18 @@ typedef enum _backslashResult
backslashResult HandleSlashCmds(PsqlSettings *pset,
const char *line,
backslashResult
HandleSlashCmds(const char *line,
PQExpBuffer query_buf,
const char **end_of_cmd);
bool process_file(const char *filename,
PsqlSettings *pset);
bool
process_file(const char *filename);
bool do_pset(const char *param,
bool
do_pset(const char *param,
const char *value,
printQueryOpt * popt,
bool quiet);
#endif
This diff is collapsed.
......@@ -8,18 +8,15 @@ char *
xstrdup(const char *string);
bool
setQFout(const char *fname, PsqlSettings *pset);
setQFout(const char *fname);
char *
simple_prompt(const char *prompt, int maxlen, bool echo);
const char *
interpolate_var(const char *name, PsqlSettings *pset);
PGresult *
PSQLexec(PsqlSettings *pset, const char *query);
PSQLexec(const char *query);
bool
SendQuery(PsqlSettings *pset, const char *query);
SendQuery(const char *query);
#endif /* COMMON_H */
#include <config.h>
#include <c.h>
#include "copy.h"
......@@ -36,7 +35,7 @@
struct copy_options
{
char *table;
char *file;
char *file; /* NULL = stdin/stdout */
bool from;
bool binary;
bool oids;
......@@ -59,7 +58,7 @@ free_copy_options(struct copy_options * ptr)
static struct copy_options *
parse_slash_copy(const char *args, PsqlSettings *pset)
parse_slash_copy(const char *args)
{
struct copy_options *result;
char *line;
......@@ -132,17 +131,15 @@ parse_slash_copy(const char *args, PsqlSettings *pset)
if (!error)
{
token = strtokx(NULL, " \t", "'", '\\', NULL, NULL);
token = strtokx(NULL, " \t", "'", '\\', &quote, NULL);
if (!token)
error = true;
else if (!quote && (strcasecmp(token, "stdin")==0 || strcasecmp(token, "stdout")==0))
result->file = NULL;
else
result->file = xstrdup(token);
}
#ifdef USE_ASSERT_CHECKING
assert(error || result->file);
#endif
if (!error)
{
token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL);
......@@ -194,8 +191,8 @@ parse_slash_copy(const char *args, PsqlSettings *pset)
if (error)
{
if (!pset->cur_cmd_interactive)
fprintf(stderr, "%s: ", pset->progname);
if (!pset.cur_cmd_interactive)
fprintf(stderr, "%s: ", pset.progname);
fputs("\\copy: parse error at ", stderr);
if (!token)
fputs("end of line", stderr);
......@@ -217,7 +214,7 @@ parse_slash_copy(const char *args, PsqlSettings *pset)
* file or route its response into the file.
*/
bool
do_copy(const char *args, PsqlSettings *pset)
do_copy(const char *args)
{
char query[128 + NAMEDATALEN];
FILE *copystream;
......@@ -226,7 +223,7 @@ do_copy(const char *args, PsqlSettings *pset)
bool success;
/* parse options */
options = parse_slash_copy(args, pset);
options = parse_slash_copy(args);
if (!options)
return false;
......@@ -242,9 +239,9 @@ do_copy(const char *args, PsqlSettings *pset)
strcat(query, "WITH OIDS ");
if (options->from)
strcat(query, "FROM stdin");
strcat(query, "FROM STDIN");
else
strcat(query, "TO stdout");
strcat(query, "TO STDOUT");
if (options->delim)
......@@ -254,24 +251,32 @@ do_copy(const char *args, PsqlSettings *pset)
strcat(query, "'");
}
if (options->null)
{
strcat(query, " WITH NULL AS '");
strcat(query, options->null);
strcat(query, "'");
}
if (options->from)
#ifndef __CYGWIN32__
{
if (options->file)
copystream = fopen(options->file, "r");
#else
copystream = fopen(options->file, "rb");
#endif
else
#ifndef __CYGWIN32__
copystream = stdin;
}
else
{
if (options->file)
copystream = fopen(options->file, "w");
#else
copystream = fopen(options->file, "wb");
#endif
else
copystream = stdout;
}
if (!copystream)
{
if (!pset->cur_cmd_interactive)
fprintf(stderr, "%s: ", pset->progname);
if (!pset.cur_cmd_interactive)
fprintf(stderr, "%s: ", pset.progname);
fprintf(stderr,
"unable to open file %s: %s\n",
options->file, strerror(errno));
......@@ -279,39 +284,39 @@ do_copy(const char *args, PsqlSettings *pset)
return false;
}
result = PSQLexec(pset, query);
result = PSQLexec(query);
switch (PQresultStatus(result))
{
case PGRES_COPY_OUT:
success = handleCopyOut(pset->db, copystream);
success = handleCopyOut(pset.db, copystream);
break;
case PGRES_COPY_IN:
success = handleCopyIn(pset->db, copystream, NULL);
success = handleCopyIn(pset.db, copystream, NULL);
break;
case PGRES_NONFATAL_ERROR:
case PGRES_FATAL_ERROR:
case PGRES_BAD_RESPONSE:
success = false;
fputs(PQerrorMessage(pset->db), stderr);
fputs(PQerrorMessage(pset.db), stderr);
break;
default:
success = false;
if (!pset->cur_cmd_interactive)
fprintf(stderr, "%s: ", pset->progname);
if (!pset.cur_cmd_interactive)
fprintf(stderr, "%s: ", pset.progname);
fprintf(stderr, "\\copy: unexpected response (%d)\n", PQresultStatus(result));
}
PQclear(result);
if (!GetVariable(pset->vars, "quiet"))
if (!success)
{
if (success)
puts("Successfully copied");
else
puts("Copy failed");
if (!pset.cur_cmd_interactive)
fprintf(stderr, "%s: ", pset.progname);
fprintf(stderr, "\\copy failed\n");
}
if (copystream != stdout && copystream != stdin)
fclose(copystream);
free_copy_options(options);
return success;
......@@ -396,7 +401,7 @@ handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt)
while (!copydone)
{ /* for each input line ... */
if (prompt && isatty(fileno(stdin)))
if (prompt && isatty(fileno(copystream)))
{
fputs(prompt, stdout);
fflush(stdout);
......
......@@ -8,7 +8,7 @@
/* handler for \copy */
bool
do_copy(const char *args, PsqlSettings *pset);
do_copy(const char *args);
/* lower level processors for copy in/out streams */
......
This diff is collapsed.
......@@ -5,30 +5,30 @@
#include "settings.h"
/* \da */
bool describeAggregates(const char *name, PsqlSettings *pset);
bool describeAggregates(const char *name);
/* \df */
bool describeFunctions(const char *name, PsqlSettings *pset, bool verbose);
bool describeFunctions(const char *name, bool verbose);
/* \dT */
bool describeTypes(const char *name, PsqlSettings *pset, bool verbose);
bool describeTypes(const char *name, bool verbose);
/* \do */
bool describeOperators(const char *name, PsqlSettings *pset);
bool describeOperators(const char *name);
/* \z (or \dp) */
bool permissionsList(const char *name, PsqlSettings *pset);
bool permissionsList(const char *name);
/* \dd */
bool objectDescription(const char *object, PsqlSettings *pset);
bool objectDescription(const char *object);
/* \d foo */
bool describeTableDetails(const char *name, PsqlSettings *pset, bool desc);
bool describeTableDetails(const char *name, bool desc);
/* \l */
bool listAllDbs(PsqlSettings *pset, bool desc);
bool listAllDbs(bool desc);
/* \dt, \di, \ds, \dS, etc. */
bool listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc);
bool listTables(const char *infotype, const char *name, bool desc);
#endif /* DESCRIBE_H */
......@@ -149,7 +149,7 @@ struct winsize
#endif
void
slashUsage(PsqlSettings *pset)
slashUsage(void)
{
bool usePipe = false;
const char *pagerenv;
......@@ -157,7 +157,7 @@ slashUsage(PsqlSettings *pset)
struct winsize screen_size;
#ifdef TIOCGWINSZ
if (pset->notty == 0 &&
if (pset.notty == 0 &&
(ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 ||
screen_size.ws_col == 0 ||
screen_size.ws_row == 0))
......@@ -169,7 +169,7 @@ slashUsage(PsqlSettings *pset)
}
#endif
if (pset->notty == 0 &&
if (pset.notty == 0 &&
(pagerenv = getenv("PAGER")) &&
(pagerenv[0] != '\0') &&
screen_size.ws_row <= 36 &&
......@@ -184,7 +184,7 @@ slashUsage(PsqlSettings *pset)
/* if you add/remove a line here, change the row test above */
fprintf(fout, " \\? help\n");
fprintf(fout, " \\c[onnect] [dbname|- [user|?]]\n"
" connect to new database (currently '%s')\n", PQdb(pset->db));
" connect to new database (currently '%s')\n", PQdb(pset.db));
fprintf(fout, " \\copy ... perform SQL COPY with data stream to the client machine");
fprintf(fout, " \\copyright show PostgreSQL usage and distribution terms\n");
fprintf(fout, " \\d <table> describe table (or view, index, sequence)\n");
......@@ -209,9 +209,10 @@ slashUsage(PsqlSettings *pset)
fprintf(fout, " \\qecho <text> write text to query output stream (see \\o)\n");
fprintf(fout, " \\r reset (clear) the query buffer\n");
fprintf(fout, " \\s [fname] print history or save it in <fname>\n");
fprintf(fout, " \\set <var> [value] set/unset internal variable\n");
fprintf(fout, " \\t don't show table headers or footers (currently %s)\n", ON(pset->popt.topt.tuples_only));
fprintf(fout, " \\x toggle expanded output (currently %s)\n", ON(pset->popt.topt.expanded));
fprintf(fout, " \\set <var> <value> set internal variable\n");
fprintf(fout, " \\t don't show table headers or footers (currently %s)\n", ON(pset.popt.topt.tuples_only));
fprintf(fout, " \\unset <var> unset (delete) internal variable\n");
fprintf(fout, " \\x toggle expanded output (currently %s)\n", ON(pset.popt.topt.expanded));
fprintf(fout, " \\w <fname> write current query buffer to a file\n");
fprintf(fout, " \\z list table access permissions\n");
fprintf(fout, " \\! [cmd] shell escape or command\n");
......
......@@ -5,7 +5,7 @@
void usage(void);
void slashUsage(PsqlSettings *pset);
void slashUsage(void);
void helpSQL(const char *topic);
......
......@@ -29,6 +29,10 @@ char *
gets_interactive(const char *prompt)
{
char *s;
#ifdef USE_HISTORY
const char *var;
static char * prev_hist = NULL;
#endif
#ifdef USE_READLINE
if (useReadline)
......@@ -45,7 +49,18 @@ gets_interactive(const char *prompt)
#ifdef USE_HISTORY
if (useHistory && s && s[0] != '\0')
{
var = GetVariable(pset.vars, "HISTCONTROL");
if (!var || (var
&& !((strcmp(var, "ignorespace") == 0 || strcmp(var, "ignoreboth") ==0) && s[0] == ' ' )
&& !((strcmp(var, "ignoredups") == 0 || strcmp(var, "ignoreboth") ==0) && prev_hist && strcmp(s, prev_hist) == 0)
))
{
free(prev_hist);
prev_hist = strdup(s);
add_history(s);
}
}
#endif
return s;
......@@ -93,14 +108,14 @@ gets_fromFile(FILE *source)
* The only "flag" right now is 1 for use readline & history.
*/
void
initializeInput(int flags, PsqlSettings *pset)
initializeInput(int flags)
{
#ifdef USE_READLINE
if (flags == 1)
{
useReadline = true;
rl_readline_name = "psql";
initialize_readline(&(pset->db));
initialize_readline(&(pset.db));
}
#endif
......@@ -110,6 +125,7 @@ initializeInput(int flags, PsqlSettings *pset)
const char *home;
useHistory = true;
SetVariable(pset.vars, "HISTSIZE", "500");
using_history();
home = getenv("HOME");
if (home)
......@@ -166,6 +182,9 @@ finishInput(void)
psql_history = (char *) malloc(strlen(home) + 20);
if (psql_history)
{
const char * var = GetVariable(pset.vars, "HISTSIZE");
if (var)
stifle_history(atoi(var));
sprintf(psql_history, "%s/.psql_history", home);
write_history(psql_history);
free(psql_history);
......
......@@ -42,7 +42,7 @@ char * gets_interactive(const char *prompt);
char * gets_fromFile(FILE *source);
void initializeInput(int flags, PsqlSettings *pset);
void initializeInput(int flags);
bool saveHistory(const char *fname);
......
#include <config.h>
#include <c.h>
#include "large_obj.h"
......@@ -33,9 +32,9 @@ _my_notice_handler(void *arg, const char *message)
static bool
handle_transaction(PsqlSettings *pset)
handle_transaction(void)
{
const char *var = GetVariable(pset->vars, "lo_transaction");
const char *var = GetVariable(pset.vars, "LO_TRANSACTION");
PGresult *res;
bool commit;
PQnoticeProcessor old_notice_hook;
......@@ -46,9 +45,9 @@ handle_transaction(PsqlSettings *pset)
commit = (var && strcmp(var, "commit") == 0);
notice[0] = '\0';
old_notice_hook = PQsetNoticeProcessor(pset->db, _my_notice_handler, NULL);
old_notice_hook = PQsetNoticeProcessor(pset.db, _my_notice_handler, NULL);
res = PSQLexec(pset, commit ? "COMMIT" : "ROLLBACK");
res = PSQLexec(commit ? "COMMIT" : "ROLLBACK");
if (!res)
return false;
......@@ -58,7 +57,7 @@ handle_transaction(PsqlSettings *pset)
(commit && strcmp(notice, "NOTICE: EndTransactionBlock and not inprogress/abort state\n") != 0))
fputs(notice, stderr);
}
else if (!GetVariableBool(pset->vars, "quiet"))
else if (!QUIET())
{
if (commit)
puts("Warning: Your transaction in progress has been committed.");
......@@ -66,7 +65,7 @@ handle_transaction(PsqlSettings *pset)
puts("Warning: Your transaction in progress has been rolled back.");
}
PQsetNoticeProcessor(pset->db, old_notice_hook, NULL);
PQsetNoticeProcessor(pset.db, old_notice_hook, NULL);
return true;
}
......@@ -78,43 +77,43 @@ handle_transaction(PsqlSettings *pset)
* Write a large object to a file
*/
bool
do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg)
do_lo_export(const char *loid_arg, const char *filename_arg)
{
PGresult *res;
int status;
bool own_transaction = true;
const char *var = GetVariable(pset->vars, "lo_transaction");
const char *var = GetVariable(pset.vars, "LO_TRANSACTION");
if (var && strcmp(var, "nothing") == 0)
own_transaction = false;
if (!pset->db)
if (!pset.db)
{
if (!pset->cur_cmd_interactive)
fprintf(stderr, "%s: ", pset->progname);
if (!pset.cur_cmd_interactive)
fprintf(stderr, "%s: ", pset.progname);
fputs("\\lo_export: not connected to a database\n", stderr);
return false;
}
if (own_transaction)
{
if (!handle_transaction(pset))
if (!handle_transaction())
return false;
if (!(res = PSQLexec(pset, "BEGIN")))
if (!(res = PSQLexec("BEGIN")))
return false;
PQclear(res);
}
status = lo_export(pset->db, atol(loid_arg), (char *) filename_arg);
status = lo_export(pset.db, atol(loid_arg), (char *) filename_arg);
if (status != 1)
{ /* of course this status is documented
* nowhere :( */
fputs(PQerrorMessage(pset->db), stderr);
fputs(PQerrorMessage(pset.db), stderr);
if (own_transaction)
{
res = PQexec(pset->db, "ROLLBACK");
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
......@@ -122,9 +121,9 @@ do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg)
if (own_transaction)
{
if (!(res = PSQLexec(pset, "COMMIT")))
if (!(res = PSQLexec("COMMIT")))
{
res = PQexec(pset->db, "ROLLBACK");
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
return false;
}
......@@ -132,7 +131,7 @@ do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg)
PQclear(res);
}
fprintf(pset->queryFout, "lo_export\n");
fprintf(pset.queryFout, "lo_export\n");
return true;
}
......@@ -145,44 +144,44 @@ do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg)
* Copy large object from file to database
*/
bool
do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_arg)
do_lo_import(const char *filename_arg, const char *comment_arg)
{
PGresult *res;
Oid loid;
char buf[1024];
unsigned int i;
bool own_transaction = true;
const char *var = GetVariable(pset->vars, "lo_transaction");
const char *var = GetVariable(pset.vars, "LO_TRANSACTION");
if (var && strcmp(var, "nothing") == 0)
own_transaction = false;
if (!pset->db)
if (!pset.db)
{
if (!pset->cur_cmd_interactive)
fprintf(stderr, "%s: ", pset->progname);
if (!pset.cur_cmd_interactive)
fprintf(stderr, "%s: ", pset.progname);
fputs("\\lo_import: not connected to a database\n", stderr);
return false;
}
if (own_transaction)
{
if (!handle_transaction(pset))
if (!handle_transaction())
return false;
if (!(res = PSQLexec(pset, "BEGIN")))
if (!(res = PSQLexec("BEGIN")))
return false;
PQclear(res);
}
loid = lo_import(pset->db, (char *) filename_arg);
loid = lo_import(pset.db, (char *) filename_arg);
if (loid == InvalidOid)
{
fputs(PQerrorMessage(pset->db), stderr);
fputs(PQerrorMessage(pset.db), stderr);
if (own_transaction)
{
res = PQexec(pset->db, "ROLLBACK");
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
......@@ -199,11 +198,11 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a
strncat(buf, &comment_arg[i], 1);
strcat(buf, "')");
if (!(res = PSQLexec(pset, buf)))
if (!(res = PSQLexec(buf)))
{
if (own_transaction)
{
res = PQexec(pset->db, "ROLLBACK");
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
......@@ -212,9 +211,9 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a
if (own_transaction)
{
if (!(res = PSQLexec(pset, "COMMIT")))
if (!(res = PSQLexec("COMMIT")))
{
res = PQexec(pset->db, "ROLLBACK");
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
return false;
}
......@@ -223,8 +222,9 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a
}
fprintf(pset->queryFout, "lo_import %d\n", loid);
pset->lastOid = loid;
fprintf(pset.queryFout, "lo_import %d\n", loid);
sprintf(buf, "%u", (unsigned int)loid);
SetVariable(pset.vars, "LASTOID", buf);
return true;
}
......@@ -237,44 +237,44 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a
* removes a large object out of the database
*/
bool
do_lo_unlink(PsqlSettings *pset, const char *loid_arg)
do_lo_unlink(const char *loid_arg)
{
PGresult *res;
int status;
Oid loid = (Oid) atol(loid_arg);
char buf[256];
bool own_transaction = true;
const char *var = GetVariable(pset->vars, "lo_transaction");
const char *var = GetVariable(pset.vars, "LO_TRANSACTION");
if (var && strcmp(var, "nothing") == 0)
own_transaction = false;
if (!pset->db)
if (!pset.db)
{
if (!pset->cur_cmd_interactive)
fprintf(stderr, "%s: ", pset->progname);
if (!pset.cur_cmd_interactive)
fprintf(stderr, "%s: ", pset.progname);
fputs("\\lo_unlink: not connected to a database\n", stderr);
return false;
}
if (own_transaction)
{
if (!handle_transaction(pset))
if (!handle_transaction())
return false;
if (!(res = PSQLexec(pset, "BEGIN")))
if (!(res = PSQLexec("BEGIN")))
return false;
PQclear(res);
}
status = lo_unlink(pset->db, loid);
status = lo_unlink(pset.db, loid);
if (status == -1)
{
fputs(PQerrorMessage(pset->db), stderr);
fputs(PQerrorMessage(pset.db), stderr);
if (own_transaction)
{
res = PQexec(pset->db, "ROLLBACK");
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
......@@ -282,11 +282,11 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg)
/* remove the comment as well */
sprintf(buf, "DELETE FROM pg_description WHERE objoid = %d", loid);
if (!(res = PSQLexec(pset, buf)))
if (!(res = PSQLexec(buf)))
{
if (own_transaction)
{
res = PQexec(pset->db, "ROLLBACK");
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
......@@ -295,9 +295,9 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg)
if (own_transaction)
{
if (!(res = PSQLexec(pset, "COMMIT")))
if (!(res = PSQLexec("COMMIT")))
{
res = PQexec(pset->db, "ROLLBACK");
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
return false;
}
......@@ -305,7 +305,7 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg)
}
fprintf(pset->queryFout, "lo_unlink %d\n", loid);
fprintf(pset.queryFout, "lo_unlink %d\n", loid);
return true;
}
......@@ -318,11 +318,11 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg)
* Show all large objects in database with comments
*/
bool
do_lo_list(PsqlSettings *pset)
do_lo_list(void)
{
PGresult *res;
char buf[1024];
printQueryOpt myopt = pset->popt;
printQueryOpt myopt = pset.popt;
strcpy(buf,
"SELECT usename as \"Owner\", substring(relname from 5) as \"ID\",\n"
......@@ -336,7 +336,7 @@ do_lo_list(PsqlSettings *pset)
"WHERE not exists (select 1 from pg_user where usesysid = relowner) AND relkind = 'l'\n"
"ORDER BY \"ID\"");
res = PSQLexec(pset, buf);
res = PSQLexec(buf);
if (!res)
return false;
......@@ -344,7 +344,7 @@ do_lo_list(PsqlSettings *pset)
myopt.nullPrint = NULL;
myopt.title = "Large objects";
printQuery(res, &myopt, pset->queryFout);
printQuery(res, &myopt, pset.queryFout);
PQclear(res);
return true;
......
......@@ -2,11 +2,10 @@
#define LARGE_OBJ_H
#include <c.h>
#include "settings.h"
bool do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg);
bool do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_arg);
bool do_lo_unlink(PsqlSettings *pset, const char *loid_arg);
bool do_lo_list(PsqlSettings *pset);
bool do_lo_export(const char *loid_arg, const char *filename_arg);
bool do_lo_import(const char *filename_arg, const char *comment_arg);
bool do_lo_unlink(const char *loid_arg);
bool do_lo_list(void);
#endif /* LARGE_OBJ_H */
#include <config.h>
#include <c.h>
#include "mainloop.h"
......@@ -26,7 +25,7 @@
* FIXME: rewrite this whole thing with flex
*/
int
MainLoop(PsqlSettings *pset, FILE *source)
MainLoop(FILE *source)
{
PQExpBuffer query_buf; /* buffer for query being accumulated */
PQExpBuffer previous_buf; /* if there isn't anything in the new buffer
......@@ -36,13 +35,14 @@ MainLoop(PsqlSettings *pset, FILE *source)
int successResult = EXIT_SUCCESS;
backslashResult slashCmdStatus;
bool eof = false; /* end of our command input? */
bool success;
char in_quote; /* == 0 for no in_quote */
bool was_bslash; /* backslash */
bool xcomment; /* in extended comment */
int paren_level;
unsigned int query_start;
int count_eof;
const char *var;
int i,
prevlen,
......@@ -56,12 +56,12 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* Save old settings */
prev_cmd_source = pset->cur_cmd_source;
prev_cmd_interactive = pset->cur_cmd_interactive;
prev_cmd_source = pset.cur_cmd_source;
prev_cmd_interactive = pset.cur_cmd_interactive;
/* Establish new source */
pset->cur_cmd_source = source;
pset->cur_cmd_interactive = ((source == stdin) && !pset->notty);
pset.cur_cmd_source = source;
pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
query_buf = createPQExpBuffer();
......@@ -79,7 +79,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* main loop to get queries and execute them */
while (!eof)
while (1)
{
if (slashCmdStatus == CMD_NEWEDIT)
{
......@@ -102,7 +102,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
* otherwise, set interactive prompt if necessary and get
* another line
*/
if (pset->cur_cmd_interactive)
if (pset.cur_cmd_interactive)
{
int prompt_status;
......@@ -117,7 +117,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
else
prompt_status = PROMPT_READY;
line = gets_interactive(get_prompt(pset, prompt_status));
line = gets_interactive(get_prompt(prompt_status));
}
else
line = gets_fromFile(source);
......@@ -125,7 +125,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* Setting this will not have effect until next line. */
die_on_error = GetVariableBool(pset->vars, "die_on_error");
die_on_error = GetVariableBool(pset.vars, "EXIT_ON_ERROR");
/*
* query_buf holds query already accumulated. line is the
......@@ -137,14 +137,47 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* No more input. Time to quit, or \i done */
if (line == NULL)
{
if (GetVariableBool(pset->vars, "echo") && !GetVariableBool(pset->vars, "quiet"))
puts("EOF");
else if (pset->cur_cmd_interactive)
putc('\n', stdout); /* just newline */
if (pset.cur_cmd_interactive)
{
bool getout = true;
/* This tries to mimic bash's IGNOREEOF feature. */
const char * val = GetVariable(pset.vars, "IGNOREEOF");
if (val)
{
long int maxeof;
char * endptr;
if (*val == '\0')
maxeof = 10;
else
{
maxeof = strtol(val, &endptr, 0);
if (*endptr != '\0') /* string not valid as a number */
maxeof = 10;
}
eof = true;
if (count_eof++ != maxeof)
getout = false; /* not quite there yet */
}
if (getout)
{
putc('\n', stdout); /* just newline */
break;
}
else
{
if (!QUIET())
printf("Use \"\\q\" to leave %s.\n", pset.progname);
continue;
}
}
else /* not interactive */
break;
}
else
count_eof = 0;
/* strip trailing backslashes, they don't have a clear meaning */
while (1)
......@@ -164,11 +197,11 @@ MainLoop(PsqlSettings *pset, FILE *source)
continue;
}
/* echo back if input is from file and flag is set */
if (!pset->cur_cmd_interactive && GetVariableBool(pset->vars, "echo"))
/* echo back if flag is set */
var = GetVariable(pset.vars, "ECHO");
if (var && strcmp(var, "full")==0)
puts(line);
fflush(stdout);
len = strlen(line);
query_start = 0;
......@@ -236,8 +269,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* colon -> substitute variable */
/* we need to be on the watch for the '::' operator */
else if (line[i] == ':' && !was_bslash &&
strspn(line+i+thislen, VALID_VARIABLE_CHARS)>0 &&
(prevlen > 0 && line[i-prevlen]!=':')
strspn(line+i+thislen, VALID_VARIABLE_CHARS)>0
)
{
size_t in_length,
......@@ -250,7 +282,11 @@ MainLoop(PsqlSettings *pset, FILE *source)
in_length = strspn(&line[i + thislen], VALID_VARIABLE_CHARS);
after = line[i + thislen + in_length];
line[i + thislen + in_length] = '\0';
value = interpolate_var(&line[i + thislen], pset);
/* if the variable doesn't exist we'll leave the string as is */
value = GetVariable(pset.vars, &line[i + thislen]);
if (value)
{
out_length = strlen(value);
new = malloc(len + out_length - (1 + in_length) + 1);
......@@ -269,6 +305,13 @@ MainLoop(PsqlSettings *pset, FILE *source)
len = strlen(new);
continue; /* reparse the just substituted */
}
else
{
/* restore overwritten character */
line[i + thislen + in_length] = after;
/* move on ... */
}
}
/* semicolon? then send query */
else if (line[i] == ';' && !was_bslash && !paren_level)
......@@ -288,7 +331,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
}
/* execute query */
success = SendQuery(pset, query_buf->data);
success = SendQuery(query_buf->data);
slashCmdStatus = success ? CMD_SEND : CMD_ERROR;
resetPQExpBuffer(previous_buf);
......@@ -314,7 +357,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
paren_level = 0;
line[i - prevlen] = '\0'; /* overwrites backslash */
/* is there anything else on the line? */
/* is there anything else on the line for the command? */
if (line[query_start + strspn(line + query_start, " \t")] != '\0')
{
/*
......@@ -328,7 +371,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
}
/* handle backslash command */
slashCmdStatus = HandleSlashCmds(pset, &line[i],
slashCmdStatus = HandleSlashCmds(&line[i],
query_buf->len>0 ? query_buf : previous_buf,
&end_of_cmd);
......@@ -342,7 +385,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
if (slashCmdStatus == CMD_SEND)
{
success = SendQuery(pset, query_buf->data);
success = SendQuery(query_buf->data);
query_start = i + thislen;
resetPQExpBuffer(previous_buf);
......@@ -350,15 +393,10 @@ MainLoop(PsqlSettings *pset, FILE *source)
resetPQExpBuffer(query_buf);
}
/* is there anything left after the backslash command? */
if (end_of_cmd)
{
/* process anything left after the backslash command */
i += end_of_cmd - &line[i];
query_start = i;
}
else
break;
}
/* stop the script after error */
......@@ -387,9 +425,9 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* In single line mode, send off the query if any */
if (query_buf->data[0] != '\0' && GetVariableBool(pset->vars, "singleline"))
if (query_buf->data[0] != '\0' && GetVariableBool(pset.vars, "SINGLELINE"))
{
success = SendQuery(pset, query_buf->data);
success = SendQuery(query_buf->data);
slashCmdStatus = success ? CMD_SEND : CMD_ERROR;
resetPQExpBuffer(previous_buf);
appendPQExpBufferStr(previous_buf, query_buf->data);
......@@ -397,7 +435,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
}
if (!success && die_on_error && !pset->cur_cmd_interactive)
if (!success && die_on_error && !pset.cur_cmd_interactive)
{
successResult = EXIT_USER;
break;
......@@ -405,18 +443,18 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* Have we lost the db connection? */
if (pset->db == NULL && !pset->cur_cmd_interactive)
if (pset.db == NULL && !pset.cur_cmd_interactive)
{
successResult = EXIT_BADCONN;
break;
}
} /* while !EOF */
} /* while !endofprogram */
destroyPQExpBuffer(query_buf);
destroyPQExpBuffer(previous_buf);
pset->cur_cmd_source = prev_cmd_source;
pset->cur_cmd_interactive = prev_cmd_interactive;
pset.cur_cmd_source = prev_cmd_source;
pset.cur_cmd_interactive = prev_cmd_interactive;
return successResult;
} /* MainLoop() */
......@@ -2,9 +2,7 @@
#define MAINLOOP_H
#include <stdio.h>
#include "settings.h"
int
MainLoop(PsqlSettings *pset, FILE *source);
int MainLoop(FILE *source);
#endif /* MAINLOOP_H */
#include <config.h>
#include <c.h>
#include "prompt.h"
......@@ -10,6 +9,7 @@
#include "settings.h"
#include "common.h"
#include "variables.h"
#ifdef WIN32
#define popen(x,y) _popen(x,y)
......@@ -22,7 +22,7 @@
* get_prompt
*
* Returns a statically allocated prompt made by interpolating certain
* tcsh style escape sequences into pset->vars "prompt1|2|3".
* tcsh style escape sequences into pset->vars "PROMPT1|2|3".
* (might not be completely multibyte safe)
*
* Defined interpolations are:
......@@ -46,8 +46,7 @@
*
* %`command` - The result of executing command in /bin/sh with trailing
* newline stripped.
* %$name$ - The value of the psql/environment/magic varible 'name'
* (same rules as for, e.g., \echo $foo)
* %$name$ - The value of the psql variable 'name'
* (those will not be rescanned for more escape sequences!)
*
*
......@@ -56,7 +55,7 @@
*--------------------------
*/
const char *
get_prompt(PsqlSettings *pset, promptStatus_t status)
get_prompt(promptStatus_t status)
{
#define MAX_PROMPT_SIZE 256
static char destination[MAX_PROMPT_SIZE + 1];
......@@ -66,11 +65,11 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
const char *prompt_string;
if (status == PROMPT_READY)
prompt_string = GetVariable(pset->vars, "prompt1");
prompt_string = GetVariable(pset.vars, "PROMPT1");
else if (status == PROMPT_CONTINUE || status == PROMPT_SINGLEQUOTE || status == PROMPT_DOUBLEQUOTE || status == PROMPT_COMMENT)
prompt_string = GetVariable(pset->vars, "prompt2");
prompt_string = GetVariable(pset.vars, "PROMPT2");
else if (status == PROMPT_COPY)
prompt_string = GetVariable(pset->vars, "prompt3");
prompt_string = GetVariable(pset.vars, "PROMPT3");
else
prompt_string = "? ";
......@@ -92,31 +91,31 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
/* Current database */
case '/':
if (pset->db)
strncpy(buf, PQdb(pset->db), MAX_PROMPT_SIZE);
if (pset.db)
strncpy(buf, PQdb(pset.db), MAX_PROMPT_SIZE);
break;
case '~':
{
const char *var;
if (pset->db)
if (pset.db)
{
if (strcmp(PQdb(pset->db), PQuser(pset->db)) == 0 ||
((var = getenv("PGDATABASE")) && strcmp(var, PQdb(pset->db)) == 0))
if (strcmp(PQdb(pset.db), PQuser(pset.db)) == 0 ||
((var = getenv("PGDATABASE")) && strcmp(var, PQdb(pset.db)) == 0))
strcpy(buf, "~");
else
strncpy(buf, PQdb(pset->db), MAX_PROMPT_SIZE);
strncpy(buf, PQdb(pset.db), MAX_PROMPT_SIZE);
}
break;
}
/* DB server hostname (long/short) */
case 'M':
case 'm':
if (pset->db)
if (pset.db)
{
if (PQhost(pset->db))
if (PQhost(pset.db))
{
strncpy(buf, PQhost(pset->db), MAX_PROMPT_SIZE);
strncpy(buf, PQhost(pset.db), MAX_PROMPT_SIZE);
if (*p == 'm')
buf[strcspn(buf, ".")] = '\0';
}
......@@ -126,13 +125,13 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
break;
/* DB server port number */
case '>':
if (pset->db && PQport(pset->db))
strncpy(buf, PQport(pset->db), MAX_PROMPT_SIZE);
if (pset.db && PQport(pset.db))
strncpy(buf, PQport(pset.db), MAX_PROMPT_SIZE);
break;
/* DB server user name */
case 'n':
if (pset->db)
strncpy(buf, PQuser(pset->db), MAX_PROMPT_SIZE);
if (pset.db)
strncpy(buf, PQuser(pset.db), MAX_PROMPT_SIZE);
break;
case '0':
......@@ -159,9 +158,9 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
switch (status)
{
case PROMPT_READY:
if (!pset->db)
if (!pset.db)
buf[0] = '!';
else if (!GetVariableBool(pset->vars, "singleline"))
else if (!GetVariableBool(pset.vars, "SINGLELINE"))
buf[0] = '=';
else
buf[0] = '^';
......@@ -189,7 +188,7 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
case '#':
{
if (pset->db && strcmp(PQuser(pset->db), "postgres") == 0)
if (pset.db && strcmp(PQuser(pset.db), "postgres") == 0)
buf[0] = '#';
else
buf[0] = '>';
......@@ -230,7 +229,7 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
name = strdup(p + 1);
nameend = strcspn(name, "$");
name[nameend] = '\0';
val = interpolate_var(name, pset);
val = GetVariable(pset.vars, name);
if (val)
strncpy(buf, val, MAX_PROMPT_SIZE);
free(name);
......
......@@ -14,7 +14,7 @@ typedef enum _promptStatus
} promptStatus_t;
const char *
get_prompt(PsqlSettings *pset, promptStatus_t status);
get_prompt(promptStatus_t status);
#endif /* PROMPT_H */
......@@ -43,11 +43,13 @@ typedef struct _psqlSettings
bool has_client_encoding; /* was PGCLIENTENCODING set on
* startup? */
Oid lastOid; /* saves oid from insert command
because people want it so badly */
char *progname; /* in case you renamed psql */
} PsqlSettings;
extern PsqlSettings pset;
#define QUIET() (GetVariableBool(pset.vars, "QUIET"))
#ifndef EXIT_SUCCESS
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment