Commit 78bc83fe authored by Bruce Momjian's avatar Bruce Momjian

* Includes tab completion. It's not magic, but it's very cool. At any

rate
  it's better than what used to be there.

* Does proper SQL "host variable" substitution as pointed out by Andreas
  Zeugwetter (thanks): select * from :foo; Also some changes in how ':'
  and ';' are treated (escape with \ to send to backend). This does
_not_
  affect the '::' cast operator, but perhaps others that contain : or ;
  (but there are none right now).

* To show description with a <something> listing, append '?' to command
  name, e.g., \df?. This seemed to be the convenient and logical
solution.
  Or append a '+' to see more useless information, e.g., \df+.

* Fixed fflush()'ing bug pointed out by Jan during the regression test
  discussion.

* Added LastOid variable. This ought to take care of TODO item "Add a
  function to return the last inserted oid, for use in psql scripts"
  (under CLIENTS)
  E.g.,
insert into foo values(...);
insert into bar values(..., :LastOid);
\echo $LastOid

* \d command shows constraints, rules, and triggers defined on the table
  (in addition to indices)

* Various fixes, optimizations, corrections

* Documentation update as well


Note: This now requires snprintf(), which, if necessary, is taken from
src/backend/port. This is certainly a little weird, but it should
suffice
until a source tree cleanup is done.

Enjoy.

--
Peter Eisentraut                  Sernanders väg 10:115
parent c83b4d1c
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
# #
# #
# IDENTIFICATION # IDENTIFICATION
# $Header: /cvsroot/pgsql/src/bin/psql/Attic/Makefile.in,v 1.17 1999/11/08 15:59:59 momjian Exp $ # $Header: /cvsroot/pgsql/src/bin/psql/Attic/Makefile.in,v 1.18 1999/11/26 04:24:16 momjian Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -30,10 +30,18 @@ endif ...@@ -30,10 +30,18 @@ endif
OBJS=command.o common.o help.o input.o stringutils.o mainloop.o \ OBJS=command.o common.o help.o input.o stringutils.o mainloop.o \
copy.o startup.o prompt.o variables.o large_obj.o print.o describe.o \ copy.o startup.o prompt.o variables.o large_obj.o print.o describe.o \
@STRDUP@ @STRERROR2@ tab-complete.o @STRDUP@ @STRERROR2@ @SNPRINTF@
all: submake psql all: submake psql
# Move this to the utils directory
ifneq (@SNPRINTF@,)
OBJS+=../../backend/port/snprintf.o
../../backend/port/snprintf.o:
$(MAKE) -C ../../backend/port snprintf.o
endif
psql: $(OBJS) $(LIBPQDIR)/libpq.a psql: $(OBJS) $(LIBPQDIR)/libpq.a
$(CC) -o psql -L$(LIBPQDIR) $(OBJS) -lpq $(LDFLAGS) $(CC) -o psql -L$(LIBPQDIR) $(OBJS) -lpq $(LDFLAGS)
...@@ -69,7 +77,7 @@ clean: ...@@ -69,7 +77,7 @@ clean:
# sql_help.h is gone, for it needs the docs in the right place to be # sql_help.h is gone, for it needs the docs in the right place to be
# regenerated. -- (pe) # regenerated. -- (pe)
distclean: clean maintainer-clean: clean
rm -f sql_help.h rm -f sql_help.h
ifeq (depend,$(wildcard depend)) ifeq (depend,$(wildcard depend))
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#endif #endif
/* functions for use in this file only */ /* functions for use in this file */
static backslashResult exec_command(const char *cmd, static backslashResult exec_command(const char *cmd,
char *const * options, char *const * options,
...@@ -41,15 +41,23 @@ static backslashResult exec_command(const char *cmd, ...@@ -41,15 +41,23 @@ static backslashResult exec_command(const char *cmd,
PQExpBuffer query_buf, PQExpBuffer query_buf,
PsqlSettings *pset); PsqlSettings *pset);
static bool static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
do_edit(const char *filename_arg, PQExpBuffer query_buf);
static char * static char * unescape(const char *source, PsqlSettings *pset);
unescape(const char *source, PsqlSettings *pset);
static bool do_connect(const char *new_dbname,
const char *new_user,
PsqlSettings *pset);
static bool
do_shell(const char *command);
static bool do_shell(const char *command);
/*
* Perhaps this should be changed to "infinity",
* but there is no convincing reason to bother
* at this point.
*/
#define NR_OPTIONS 16
/*---------- /*----------
...@@ -78,7 +86,7 @@ HandleSlashCmds(PsqlSettings *pset, ...@@ -78,7 +86,7 @@ HandleSlashCmds(PsqlSettings *pset,
{ {
backslashResult status = CMD_SKIP_LINE; backslashResult status = CMD_SKIP_LINE;
char *my_line; char *my_line;
char *options[17] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; char *options[NR_OPTIONS+1];
char *token; char *token;
const char *options_string = NULL; const char *options_string = NULL;
const char *cmd; const char *cmd;
...@@ -120,7 +128,7 @@ HandleSlashCmds(PsqlSettings *pset, ...@@ -120,7 +128,7 @@ HandleSlashCmds(PsqlSettings *pset,
i = 0; i = 0;
token = strtokx(options_string, " \t", "\"'`", '\\', &quote, &pos); token = strtokx(options_string, " \t", "\"'`", '\\', &quote, &pos);
for (i = 0; token && i < 16; i++) for (i = 0; token && i < NR_OPTIONS; i++)
{ {
switch (quote) switch (quote)
{ {
...@@ -194,14 +202,15 @@ HandleSlashCmds(PsqlSettings *pset, ...@@ -194,14 +202,15 @@ HandleSlashCmds(PsqlSettings *pset,
options[i] = xstrdup(interpolate_var(token + 1, pset)); options[i] = xstrdup(interpolate_var(token + 1, pset));
else else
options[i] = xstrdup(token); options[i] = xstrdup(token);
break;
} }
if (continue_parse) if (continue_parse)
break; break;
token = strtokx(NULL, " \t", "\"'`", '\\', &quote, &pos); token = strtokx(NULL, " \t", "\"'`", '\\', &quote, &pos);
} } /* for */
options[i] = NULL;
} }
cmd = my_line; cmd = my_line;
...@@ -216,11 +225,11 @@ HandleSlashCmds(PsqlSettings *pset, ...@@ -216,11 +225,11 @@ HandleSlashCmds(PsqlSettings *pset,
* arguments to start immediately after the command, but that is * arguments to start immediately after the command, but that is
* no longer encouraged. * no longer encouraged.
*/ */
const char *new_options[17]; const char *new_options[NR_OPTIONS+1];
char new_cmd[2]; char new_cmd[2];
int i; int i;
for (i = 1; i < 17; i++) for (i = 1; i < NR_OPTIONS+1; i++)
new_options[i] = options[i - 1]; new_options[i] = options[i - 1];
new_options[0] = cmd + 1; new_options[0] = cmd + 1;
...@@ -249,7 +258,7 @@ HandleSlashCmds(PsqlSettings *pset, ...@@ -249,7 +258,7 @@ HandleSlashCmds(PsqlSettings *pset,
} }
/* clean up */ /* clean up */
for (i = 0; i < 16 && options[i]; i++) for (i = 0; i < NR_OPTIONS && options[i]; i++)
free(options[i]); free(options[i]);
free(my_line); free(my_line);
...@@ -274,10 +283,7 @@ exec_command(const char *cmd, ...@@ -274,10 +283,7 @@ exec_command(const char *cmd,
backslashResult status = CMD_SKIP_LINE; backslashResult status = CMD_SKIP_LINE;
/* /* \a -- toggle field alignment This makes little sense but we keep it around. */
* \a -- toggle field alignment This is deprecated and makes no sense,
* but we keep it around.
*/
if (strcmp(cmd, "a") == 0) if (strcmp(cmd, "a") == 0)
{ {
if (pset->popt.topt.format != PRINT_ALIGNED) if (pset->popt.topt.format != PRINT_ALIGNED)
...@@ -287,22 +293,19 @@ exec_command(const char *cmd, ...@@ -287,22 +293,19 @@ exec_command(const char *cmd,
} }
/* /* \C -- override table title (formerly change HTML caption) */
* \C -- override table title (formerly change HTML caption) This is
* deprecated.
*/
else if (strcmp(cmd, "C") == 0) else if (strcmp(cmd, "C") == 0)
success = do_pset("title", options[0], &pset->popt, quiet); success = do_pset("title", options[0], &pset->popt, quiet);
/*----------
/*
* \c or \connect -- connect to new database or as different user * \c or \connect -- connect to new database or as different user
* *
* \c foo bar : connect to db "foo" as user "bar" \c foo [-] : * \c foo bar: connect to db "foo" as user "bar"
* connect to db "foo" as current user \c - bar : connect to * \c foo [-]: connect to db "foo" as current user
* current db as user "bar" \c : connect to default db as * \c - bar: connect to current db as user "bar"
* default user * \c: connect to default db as default user
*----------
*/ */
else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0) else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
{ {
...@@ -335,35 +338,39 @@ exec_command(const char *cmd, ...@@ -335,35 +338,39 @@ exec_command(const char *cmd,
/* \d* commands */ /* \d* commands */
else if (cmd[0] == 'd') else if (cmd[0] == 'd')
{ {
bool show_verbose = strchr(cmd, '+') ? true : false;
bool show_desc = strchr(cmd, '?') ? true : false;
switch (cmd[1]) switch (cmd[1])
{ {
case '\0': case '\0':
case '?':
if (options[0]) if (options[0])
success = describeTableDetails(options[0], pset); success = describeTableDetails(options[0], pset, show_desc);
else else
success = listTables("tvs", NULL, pset); /* standard listing of /* standard listing of interesting things */
* interesting things */ success = listTables("tvs", NULL, pset, show_desc);
break; break;
case 'a': case 'a':
success = describeAggregates(options[0], pset); success = describeAggregates(options[0], pset, show_verbose, show_desc);
break; break;
case 'd': case 'd':
success = objectDescription(options[0], pset); success = objectDescription(options[0], pset);
break; break;
case 'f': case 'f':
success = describeFunctions(options[0], pset); success = describeFunctions(options[0], pset, show_verbose, show_desc);
break; break;
case 'l': case 'l':
success = do_lo_list(pset); success = do_lo_list(pset, show_desc);
break; break;
case 'o': case 'o':
success = describeOperators(options[0], pset); success = describeOperators(options[0], pset, show_verbose, show_desc);
break; break;
case 'p': case 'p':
success = permissionsList(options[0], pset); success = permissionsList(options[0], pset);
break; break;
case 'T': case 'T':
success = describeTypes(options[0], pset); success = describeTypes(options[0], pset, show_verbose, show_desc);
break; break;
case 't': case 't':
case 'v': case 'v':
...@@ -371,9 +378,9 @@ exec_command(const char *cmd, ...@@ -371,9 +378,9 @@ exec_command(const char *cmd,
case 's': case 's':
case 'S': case 'S':
if (cmd[1] == 'S' && cmd[2] == '\0') if (cmd[1] == 'S' && cmd[2] == '\0')
success = listTables("Stvs", NULL, pset); success = listTables("Stvs", NULL, pset, show_desc);
else else
success = listTables(&cmd[1], options[0], pset); success = listTables(&cmd[1], options[0], pset, show_desc);
break; break;
default: default:
status = CMD_UNKNOWN; status = CMD_UNKNOWN;
...@@ -399,14 +406,10 @@ exec_command(const char *cmd, ...@@ -399,14 +406,10 @@ exec_command(const char *cmd,
fputs("\n", stdout); fputs("\n", stdout);
} }
/* /* \f -- change field separator */
* \f -- change field separator (This is deprecated in favour of
* \pset.)
*/
else if (strcmp(cmd, "f") == 0) else if (strcmp(cmd, "f") == 0)
success = do_pset("fieldsep", options[0], &pset->popt, quiet); success = do_pset("fieldsep", options[0], &pset->popt, quiet);
/* \g means send query */ /* \g means send query */
else if (strcmp(cmd, "g") == 0) else if (strcmp(cmd, "g") == 0)
{ {
...@@ -419,12 +422,27 @@ exec_command(const char *cmd, ...@@ -419,12 +422,27 @@ exec_command(const char *cmd,
/* help */ /* help */
else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0) else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
helpSQL(options_string); {
char buf[256] = "";
int i;
for (i=0; options && options[i] && strlen(buf)<255; i++)
{
strncat(buf, options[i], 255 - strlen(buf));
if (strlen(buf)<255 && options[i+1])
strcat(buf, " ");
}
buf[255] = '\0';
helpSQL(buf);
}
/* HTML mode */ /* HTML mode */
else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0) else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
success = do_pset("format", "html", &pset->popt, quiet); {
if (pset->popt.topt.format != PRINT_HTML)
success = do_pset("format", "html", &pset->popt, quiet);
else
success = do_pset("format", "aligned", &pset->popt, quiet);
}
/* \i is include file */ /* \i is include file */
...@@ -439,9 +457,12 @@ exec_command(const char *cmd, ...@@ -439,9 +457,12 @@ exec_command(const char *cmd,
success = process_file(options[0], pset); success = process_file(options[0], pset);
} }
/* \l is list databases */ /* \l is list databases */
else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0) else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0)
success = listAllDbs(pset); success = listAllDbs(pset, false);
else if (strcmp(cmd, "l?") == 0 || strcmp(cmd, "list?") == 0)
success = listAllDbs(pset, true);
/* large object things */ /* large object things */
...@@ -470,7 +491,9 @@ exec_command(const char *cmd, ...@@ -470,7 +491,9 @@ exec_command(const char *cmd,
} }
else if (strcmp(cmd + 3, "list") == 0) else if (strcmp(cmd + 3, "list") == 0)
success = do_lo_list(pset); success = do_lo_list(pset, false);
else if (strcmp(cmd + 3, "list?") == 0)
success = do_lo_list(pset, true);
else if (strcmp(cmd + 3, "unlink") == 0) else if (strcmp(cmd + 3, "unlink") == 0)
{ {
...@@ -828,7 +851,7 @@ unescape(const char *source, PsqlSettings *pset) ...@@ -828,7 +851,7 @@ unescape(const char *source, PsqlSettings *pset)
* Returns true if all ok, false if the new connection couldn't be established * Returns true if all ok, false if the new connection couldn't be established
* but the old one was set back. Otherwise it terminates the program. * but the old one was set back. Otherwise it terminates the program.
*/ */
bool static bool
do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset) do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset)
{ {
PGconn *oldconn = pset->db; PGconn *oldconn = pset->db;
......
...@@ -29,10 +29,6 @@ backslashResult HandleSlashCmds(PsqlSettings *pset, ...@@ -29,10 +29,6 @@ backslashResult HandleSlashCmds(PsqlSettings *pset,
PQExpBuffer query_buf, PQExpBuffer query_buf,
const char **end_of_cmd); const char **end_of_cmd);
bool do_connect(const char *new_dbname,
const char *new_user,
PsqlSettings *pset);
bool process_file(const char *filename, bool process_file(const char *filename,
PsqlSettings *pset); PsqlSettings *pset);
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
#include "common.h" #include "common.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_TERMIOS_H #ifdef HAVE_TERMIOS_H
#include <termios.h> #include <termios.h>
#endif #endif
#include <stdio.h>
#include <string.h>
#ifndef HAVE_STRDUP #ifndef HAVE_STRDUP
#include <strdup.h> #include <strdup.h>
#endif #endif
...@@ -15,9 +15,12 @@ ...@@ -15,9 +15,12 @@
#include <assert.h> #include <assert.h>
#ifndef WIN32 #ifndef WIN32
#include <unistd.h> /* for write() */ #include <unistd.h> /* for write() */
#else
#include <io.h> /* for _write() */
#endif #endif
#include <libpq-fe.h> #include <libpq-fe.h>
#include <postgres_ext.h>
#include <pqsignal.h> #include <pqsignal.h>
#include <version.h> #include <version.h>
...@@ -30,6 +33,7 @@ ...@@ -30,6 +33,7 @@
#ifdef WIN32 #ifdef WIN32
#define popen(x,y) _popen(x,y) #define popen(x,y) _popen(x,y)
#define pclose(x) _pclose(x) #define pclose(x) _pclose(x)
#define write(a,b,c) _write(a,b,c)
#endif #endif
...@@ -210,11 +214,13 @@ simple_prompt(const char *prompt, int maxlen, bool echo) ...@@ -210,11 +214,13 @@ simple_prompt(const char *prompt, int maxlen, bool echo)
/* /*
* interpolate_var() * interpolate_var()
* *
* If the variable is a regular psql variable, just return its value. * The idea here is that certain variables have a "magic" meaning, such as
* If it's a magic variable, return that value. * LastOid. However, you can assign to those variables, but that will shadow
* the magic meaning, until you unset it. If nothing matches, the value of
* the environment variable is used.
* *
* This function only returns NULL if you feed in NULL. Otherwise it's ready for * This function only returns NULL if you feed in NULL's (don't do that).
* immediate consumption. * Otherwise, the return value is ready for immediate consumption.
*/ */
const char * const char *
interpolate_var(const char *name, PsqlSettings *pset) interpolate_var(const char *name, PsqlSettings *pset)
...@@ -229,14 +235,9 @@ interpolate_var(const char *name, PsqlSettings *pset) ...@@ -229,14 +235,9 @@ interpolate_var(const char *name, PsqlSettings *pset)
return NULL; return NULL;
#endif #endif
if (strspn(name, VALID_VARIABLE_CHARS) == strlen(name)) var = GetVariable(pset->vars, name);
{ if (var)
var = GetVariable(pset->vars, name); return var;
if (var)
return var;
else
return "";
}
/* otherwise return magic variable */ /* otherwise return magic variable */
...@@ -279,11 +280,16 @@ interpolate_var(const char *name, PsqlSettings *pset) ...@@ -279,11 +280,16 @@ interpolate_var(const char *name, PsqlSettings *pset)
return ""; return "";
} }
/* if (strcmp(name, "LastOid") == 0)
* env vars (if env vars are all caps there should be no prob, {
* otherwise you're on your own static char buf[24];
*/ if (pset->lastOid == InvalidOid)
return "";
sprintf(buf, "%u", pset->lastOid);
return buf;
}
/* env vars */
if ((var = getenv(name))) if ((var = getenv(name)))
return var; return var;
...@@ -293,42 +299,31 @@ interpolate_var(const char *name, PsqlSettings *pset) ...@@ -293,42 +299,31 @@ interpolate_var(const char *name, PsqlSettings *pset)
/* /*
* Code to support command cancellation. * Code to support query cancellation
*
* If interactive, we enable a SIGINT signal catcher before we start a
* query that sends a cancel request to the backend.
* Note that sending the cancel directly from the signal handler is safe
* only because PQrequestCancel is carefully written to make it so. We
* have to be very careful what else we do in the signal handler.
* *
* Writing on stderr is potentially dangerous, if the signal interrupted * Before we start a query, we enable a SIGINT signal catcher that sends a
* some stdio operation on stderr. On Unix we can avoid trouble by using * cancel request to the backend. Note that sending the cancel directly from
* write() instead; on Windows that's probably not workable, but we can * the signal handler is safe because PQrequestCancel() is written to make it
* at least avoid trusting printf by using the more primitive fputs(). * so. We have to be very careful what else we do in the signal handler. This
* includes using write() for output.
*/ */
PGconn *cancelConn; static PGconn *cancelConn;
#ifdef WIN32
#define safe_write_stderr(String) fputs(s, stderr)
#else
#define safe_write_stderr(String) write(fileno(stderr), String, strlen(String))
#endif
#define write_stderr(String) write(fileno(stderr), String, strlen(String))
static void static void
handle_sigint(SIGNAL_ARGS) handle_sigint(SIGNAL_ARGS)
{ {
/* accept signal if no connection */
if (cancelConn == NULL) if (cancelConn == NULL)
exit(1); return;
/* Try to send cancel request */ /* Try to send cancel request */
if (PQrequestCancel(cancelConn)) if (PQrequestCancel(cancelConn))
safe_write_stderr("\nCANCEL request sent\n"); write_stderr("\nCancel request sent\n");
else else
{ {
safe_write_stderr("\nCould not send cancel request: "); write_stderr("\nCould not send cancel request: ");
safe_write_stderr(PQerrorMessage(cancelConn)); write_stderr(PQerrorMessage(cancelConn));
} }
} }
...@@ -348,7 +343,7 @@ PSQLexec(PsqlSettings *pset, const char *query) ...@@ -348,7 +343,7 @@ PSQLexec(PsqlSettings *pset, const char *query)
if (!pset->db) if (!pset->db)
{ {
fputs("You are not currently connected to a database.\n", stderr); fputs("You are currently not connected to a database.\n", stderr);
return NULL; return NULL;
} }
...@@ -367,7 +362,7 @@ PSQLexec(PsqlSettings *pset, const char *query) ...@@ -367,7 +362,7 @@ PSQLexec(PsqlSettings *pset, const char *query)
res = PQexec(pset->db, query); res = PQexec(pset->db, query);
pqsignal(SIGINT, SIG_DFL); /* no control-C is back to normal */ pqsignal(SIGINT, SIG_DFL); /* now control-C is back to normal */
if (PQstatus(pset->db) == CONNECTION_BAD) if (PQstatus(pset->db) == CONNECTION_BAD)
{ {
...@@ -393,7 +388,7 @@ PSQLexec(PsqlSettings *pset, const char *query) ...@@ -393,7 +388,7 @@ PSQLexec(PsqlSettings *pset, const char *query)
return res; return res;
else else
{ {
fprintf(stderr, "%s", PQerrorMessage(pset->db)); fputs(PQerrorMessage(pset->db), pset->queryFout);
PQclear(res); PQclear(res);
return NULL; return NULL;
} }
...@@ -422,7 +417,7 @@ SendQuery(PsqlSettings *pset, const char *query) ...@@ -422,7 +417,7 @@ SendQuery(PsqlSettings *pset, const char *query)
if (!pset->db) if (!pset->db)
{ {
fputs("You are not currently connected to a database.\n", stderr); fputs("You are currently not connected to a database.\n", stderr);
return false; return false;
} }
...@@ -430,10 +425,10 @@ SendQuery(PsqlSettings *pset, const char *query) ...@@ -430,10 +425,10 @@ SendQuery(PsqlSettings *pset, const char *query)
{ {
char buf[3]; char buf[3];
fprintf(stdout, "***(Single step mode: Verify query)*********************************************\n" printf("***(Single step mode: Verify query)*********************************************\n"
"QUERY: %s\n" "%s\n"
"***(press return to proceed or enter x and return to cancel)********************\n", "***(press return to proceed or enter x and return to cancel)********************\n",
query); query);
fflush(stdout); fflush(stdout);
fgets(buf, 3, stdin); fgets(buf, 3, stdin);
if (buf[0] == 'x') if (buf[0] == 'x')
...@@ -492,11 +487,15 @@ SendQuery(PsqlSettings *pset, const char *query) ...@@ -492,11 +487,15 @@ SendQuery(PsqlSettings *pset, const char *query)
break; break;
case PGRES_COMMAND_OK: case PGRES_COMMAND_OK:
success = true; success = true;
fprintf(pset->queryFout, "%s\n", PQcmdStatus(results)); pset->lastOid = PQoidValue(results);
if (!GetVariableBool(pset->vars, "quiet")) {
fprintf(pset->queryFout, "%s\n", PQcmdStatus(results));
fflush(pset->queryFout);
}
break; break;
case PGRES_COPY_OUT: case PGRES_COPY_OUT:
if (pset->cur_cmd_interactive && !GetVariable(pset->vars, "quiet")) if (pset->cur_cmd_interactive && !GetVariableBool(pset->vars, "quiet"))
puts("Copy command returns:"); puts("Copy command returns:");
success = handleCopyOut(pset->db, pset->queryFout); success = handleCopyOut(pset->db, pset->queryFout);
...@@ -516,6 +515,7 @@ SendQuery(PsqlSettings *pset, const char *query) ...@@ -516,6 +515,7 @@ SendQuery(PsqlSettings *pset, const char *query)
case PGRES_BAD_RESPONSE: case PGRES_BAD_RESPONSE:
success = false; success = false;
fputs(PQerrorMessage(pset->db), pset->queryFout); fputs(PQerrorMessage(pset->db), pset->queryFout);
fflush(pset->queryFout);
break; break;
} }
......
This diff is collapsed.
#ifndef DESCRIBE_H #ifndef DESCRIBE_H
#define DESCRIBE_H #define DESCRIBE_H
#include <c.h>
#include "settings.h" #include "settings.h"
/* \da */ /* \da */
bool bool describeAggregates(const char *name, PsqlSettings *pset, bool verbose, bool desc);
describeAggregates(const char *name, PsqlSettings *pset);
/* \df */ /* \df */
bool bool describeFunctions(const char *name, PsqlSettings *pset, bool verbose, bool desc);
describeFunctions(const char *name, PsqlSettings *pset);
/* \dT */ /* \dT */
bool bool describeTypes(const char *name, PsqlSettings *pset, bool verbose, bool desc);
describeTypes(const char *name, PsqlSettings *pset);
/* \do */ /* \do */
bool bool describeOperators(const char *name, PsqlSettings *pset, bool verbose, bool desc);
describeOperators(const char *name, PsqlSettings *pset);
/* \dp (formerly \z) */ /* \z (or \dp) */
bool bool permissionsList(const char *name, PsqlSettings *pset);
permissionsList(const char *name, PsqlSettings *pset);
/* \dd */ /* \dd */
bool bool objectDescription(const char *object, PsqlSettings *pset);
objectDescription(const char *object, PsqlSettings *pset);
/* \d foo */ /* \d foo */
bool bool describeTableDetails(const char *name, PsqlSettings *pset, bool desc);
describeTableDetails(const char *name, PsqlSettings *pset);
/* \l */ /* \l */
bool bool listAllDbs(PsqlSettings *pset, bool desc);
listAllDbs(PsqlSettings *pset);
/* \dt, \di, \dS, etc. */ /* \dt, \di, \ds, \dS, etc. */
bool bool listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc);
listTables(const char *infotype, const char *name, PsqlSettings *pset);
#endif /* DESCRIBE_H */ #endif /* DESCRIBE_H */
...@@ -180,7 +180,7 @@ slashUsage(PsqlSettings *pset) ...@@ -180,7 +180,7 @@ slashUsage(PsqlSettings *pset)
fprintf(fout, " \\c[onnect] [dbname|- [user|?]] -- connect to new database (now '%s')\n", PQdb(pset->db)); fprintf(fout, " \\c[onnect] [dbname|- [user|?]] -- connect to new database (now '%s')\n", PQdb(pset->db));
fprintf(fout, " \\copy [binary] <table> [with oids] {from|to} <fname>[using delimiters '<char>']\n"); fprintf(fout, " \\copy [binary] <table> [with oids] {from|to} <fname>[using delimiters '<char>']\n");
fprintf(fout, " \\copyright -- show PostgreSQL copyright\n"); fprintf(fout, " \\copyright -- show PostgreSQL copyright\n");
fprintf(fout, " \\d -- list tables, views, and sequences\n"); fprintf(fout, " \\d <table> -- describe table (or view, index, sequence)\n");
fprintf(fout, " \\d{i|s|t|v|S}-- list only indices/sequences/tables/views/system tables\n"); fprintf(fout, " \\d{i|s|t|v|S}-- list only indices/sequences/tables/views/system tables\n");
fprintf(fout, " \\da -- list aggregates\n"); fprintf(fout, " \\da -- list aggregates\n");
fprintf(fout, " \\dd [object] -- list comment for table, type, function, or operator\n"); fprintf(fout, " \\dd [object] -- list comment for table, type, function, or operator\n");
......
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
#include <pqexpbuffer.h> #include <pqexpbuffer.h>
/* Note that this file does not depend on any other files in psql. */ #include "settings.h"
#include "tab-complete.h"
/* Runtime options for turning off readline and history */ /* Runtime options for turning off readline and history */
/* (of course there is no runtime command for doing that :) */ /* (of course there is no runtime command for doing that :) */
...@@ -96,13 +97,14 @@ gets_fromFile(FILE *source) ...@@ -96,13 +97,14 @@ gets_fromFile(FILE *source)
* The only "flag" right now is 1 for use readline & history. * The only "flag" right now is 1 for use readline & history.
*/ */
void void
initializeInput(int flags) initializeInput(int flags, PsqlSettings *pset)
{ {
#ifdef USE_READLINE #ifdef USE_READLINE
if (flags == 1) if (flags == 1)
{ {
useReadline = true; useReadline = true;
rl_readline_name = "psql"; rl_readline_name = "psql";
initialize_readline(&(pset->db));
} }
#endif #endif
......
...@@ -37,20 +37,15 @@ ...@@ -37,20 +37,15 @@
#endif #endif
char * char * gets_interactive(const char *prompt);
gets_interactive(const char *prompt);
char * char * gets_fromFile(FILE *source);
gets_fromFile(FILE *source);
void void initializeInput(int flags, PsqlSettings *pset);
initializeInput(int flags);
bool bool saveHistory(const char *fname);
saveHistory(const char *fname);
void void finishInput(void);
finishInput(void);
#endif #endif
...@@ -220,6 +220,7 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a ...@@ -220,6 +220,7 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a
fprintf(pset->queryFout, "lo_import %d\n", loid); fprintf(pset->queryFout, "lo_import %d\n", loid);
pset->lastOid = loid;
return true; return true;
} }
...@@ -311,21 +312,20 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg) ...@@ -311,21 +312,20 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg)
* Show all large objects in database, with comments if desired * Show all large objects in database, with comments if desired
*/ */
bool bool
do_lo_list(PsqlSettings *pset) do_lo_list(PsqlSettings *pset, bool desc)
{ {
PGresult *res; PGresult *res;
char descbuf[512]; char buf[512];
printQueryOpt myopt = pset->popt; printQueryOpt myopt = pset->popt;
descbuf[0] = '\0'; strcpy(buf, "SELECT usename as \"Owner\", substring(relname from 5) as \"ID\"");
strcat(descbuf, "SELECT usename as \"Owner\", substring(relname from 5) as \"ID\""); if (desc)
if (GetVariableBool(pset->vars, "description")) strcat(buf, ",\n obj_description(pg_class.oid) as \"Description\"");
strcat(descbuf, ",\n obj_description(pg_class.oid) as \"Description\""); strcat(buf, "\nFROM pg_class, pg_user\n"
strcat(descbuf, "\nFROM pg_class, pg_user\n"
"WHERE usesysid = relowner AND relkind = 'l'\n" "WHERE usesysid = relowner AND relkind = 'l'\n"
"ORDER BY \"ID\""); "ORDER BY \"ID\"");
res = PSQLexec(pset, descbuf); res = PSQLexec(pset, buf);
if (!res) if (!res)
return false; return false;
......
#ifndef LARGE_OBJ_H #ifndef LARGE_OBJ_H
#define LARGE_OBJ_H #define LARGE_OBJ_H
#include <c.h>
#include "settings.h" #include "settings.h"
bool do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg); 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_import(PsqlSettings *pset, const char *filename_arg, const char *comment_arg);
bool do_lo_unlink(PsqlSettings *pset, const char *loid_arg); bool do_lo_unlink(PsqlSettings *pset, const char *loid_arg);
bool do_lo_list(PsqlSettings *pset); bool do_lo_list(PsqlSettings *pset, bool desc);
#endif /* LARGE_OBJ_H */ #endif /* LARGE_OBJ_H */
...@@ -16,19 +16,20 @@ ...@@ -16,19 +16,20 @@
/* MainLoop() /*
* Main processing loop for reading lines of input * Main processing loop for reading lines of input
* and sending them to the backend. * and sending them to the backend.
* *
* This loop is re-entrant. May be called by \i command * This loop is re-entrant. May be called by \i command
* which reads input from a file. * which reads input from a file.
*
* FIXME: rewrite this whole thing with flex
*/ */
int int
MainLoop(PsqlSettings *pset, FILE *source) MainLoop(PsqlSettings *pset, FILE *source)
{ {
PQExpBuffer query_buf; /* buffer for query being accumulated */ PQExpBuffer query_buf; /* buffer for query being accumulated */
char *line; /* current line of input */ char *line; /* current line of input */
char *xcomment; /* start of extended comment */
int len; /* length of the line */ int len; /* length of the line */
int successResult = EXIT_SUCCESS; int successResult = EXIT_SUCCESS;
backslashResult slashCmdStatus; backslashResult slashCmdStatus;
...@@ -37,6 +38,7 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -37,6 +38,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
bool success; bool success;
char in_quote; /* == 0 for no in_quote */ char in_quote; /* == 0 for no in_quote */
bool was_bslash; /* backslash */ bool was_bslash; /* backslash */
bool xcomment; /* in extended comment */
int paren_level; int paren_level;
unsigned int query_start; unsigned int query_start;
...@@ -49,7 +51,6 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -49,7 +51,6 @@ MainLoop(PsqlSettings *pset, FILE *source)
bool prev_cmd_interactive; bool prev_cmd_interactive;
bool die_on_error; bool die_on_error;
const char *interpol_char;
/* Save old settings */ /* Save old settings */
...@@ -68,7 +69,7 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -68,7 +69,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
xcomment = NULL; xcomment = false;
in_quote = 0; in_quote = 0;
paren_level = 0; paren_level = 0;
slashCmdStatus = CMD_UNKNOWN; /* set default */ slashCmdStatus = CMD_UNKNOWN; /* set default */
...@@ -87,7 +88,7 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -87,7 +88,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
line = strdup(query_buf->data); line = strdup(query_buf->data);
resetPQExpBuffer(query_buf); resetPQExpBuffer(query_buf);
/* reset parsing state since we are rescanning whole query */ /* reset parsing state since we are rescanning whole query */
xcomment = NULL; xcomment = false;
in_quote = 0; in_quote = 0;
paren_level = 0; paren_level = 0;
} }
...@@ -106,7 +107,7 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -106,7 +107,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
prompt_status = PROMPT_SINGLEQUOTE; prompt_status = PROMPT_SINGLEQUOTE;
else if (in_quote && in_quote == '"') else if (in_quote && in_quote == '"')
prompt_status = PROMPT_DOUBLEQUOTE; prompt_status = PROMPT_DOUBLEQUOTE;
else if (xcomment != NULL) else if (xcomment)
prompt_status = PROMPT_COMMENT; prompt_status = PROMPT_COMMENT;
else if (query_buf->len > 0) else if (query_buf->len > 0)
prompt_status = PROMPT_CONTINUE; prompt_status = PROMPT_CONTINUE;
...@@ -120,10 +121,11 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -120,10 +121,11 @@ MainLoop(PsqlSettings *pset, FILE *source)
} }
/* Setting these will not have effect until next line */ /* Setting this will not have effect until next line. (Faster.
Also think about what happens if there is an error processing
_this_ command.)
*/
die_on_error = GetVariableBool(pset->vars, "die_on_error"); die_on_error = GetVariableBool(pset->vars, "die_on_error");
interpol_char = GetVariable(pset->vars, "sql_interpol");;
/* /*
* query_buf holds query already accumulated. line is the * query_buf holds query already accumulated. line is the
...@@ -144,11 +146,6 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -144,11 +146,6 @@ MainLoop(PsqlSettings *pset, FILE *source)
continue; continue;
} }
/* not currently inside an extended comment? */
if (xcomment)
xcomment = line;
/* strip trailing backslashes, they don't have a clear meaning */ /* strip trailing backslashes, they don't have a clear meaning */
while (1) while (1)
{ {
...@@ -160,52 +157,6 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -160,52 +157,6 @@ MainLoop(PsqlSettings *pset, FILE *source)
break; break;
} }
/* echo back if input is from file and flag is set */
if (!pset->cur_cmd_interactive && GetVariableBool(pset->vars, "echo"))
fprintf(stderr, "%s\n", line);
/* interpolate variables into SQL */
len = strlen(line);
thislen = PQmblen(line);
for (i = 0; line[i]; i += (thislen = PQmblen(&line[i])))
{
if (interpol_char && interpol_char[0] != '\0' && interpol_char[0] == line[i])
{
size_t in_length,
out_length;
const char *value;
char *new;
bool closer; /* did we have a closing delimiter
* or just an end of line? */
in_length = strcspn(&line[i + thislen], interpol_char);
closer = line[i + thislen + in_length] == line[i];
line[i + thislen + in_length] = '\0';
value = interpolate_var(&line[i + thislen], pset);
out_length = strlen(value);
new = malloc(len + out_length - (in_length + (closer ? 2 : 1)) + 1);
if (!new)
{
perror("malloc");
exit(EXIT_FAILURE);
}
new[0] = '\0';
strncat(new, line, i);
strcat(new, value);
if (closer)
strcat(new, line + i + 2 + in_length);
free(line);
line = new;
i += out_length;
}
}
/* nothing left on line? then ignore */ /* nothing left on line? then ignore */
if (line[0] == '\0') if (line[0] == '\0')
{ {
...@@ -213,6 +164,12 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -213,6 +164,12 @@ MainLoop(PsqlSettings *pset, FILE *source)
continue; continue;
} }
/* echo back if input is from file and flag is set */
if (!pset->cur_cmd_interactive && GetVariableBool(pset->vars, "echo"))
puts(line);
slashCmdStatus = CMD_UNKNOWN; slashCmdStatus = CMD_UNKNOWN;
len = strlen(line); len = strlen(line);
...@@ -224,24 +181,15 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -224,24 +181,15 @@ MainLoop(PsqlSettings *pset, FILE *source)
* The current character is at line[i], the prior character at line[i * The current character is at line[i], the prior character at line[i
* - prevlen], the next character at line[i + thislen]. * - prevlen], the next character at line[i + thislen].
*/ */
prevlen = 0; #define ADVANCE_1 (prevlen = thislen, i += thislen, thislen = PQmblen(line+i))
thislen = (len > 0) ? PQmblen(line) : 0;
#define ADVANCE_1 (prevlen = thislen, i += thislen, thislen = PQmblen(line+i))
success = true; success = true;
for (i = 0; i < len; ADVANCE_1) for (i = 0, prevlen = 0, thislen = (len > 0) ? PQmblen(line) : 0;
i < len;
ADVANCE_1)
{ {
if (!success && die_on_error)
break;
/* was the previous character a backslash? */ /* was the previous character a backslash? */
if (i > 0 && line[i - prevlen] == '\\') was_bslash = (i > 0 && line[i - prevlen] == '\\');
was_bslash = true;
else
was_bslash = false;
/* in quote? */ /* in quote? */
if (in_quote) if (in_quote)
...@@ -256,11 +204,11 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -256,11 +204,11 @@ MainLoop(PsqlSettings *pset, FILE *source)
in_quote = line[i]; in_quote = line[i];
/* in extended comment? */ /* in extended comment? */
else if (xcomment != NULL) else if (xcomment)
{ {
if (line[i] == '*' && line[i + thislen] == '/') if (line[i] == '*' && line[i + thislen] == '/')
{ {
xcomment = NULL; xcomment = false;
ADVANCE_1; ADVANCE_1;
} }
} }
...@@ -268,7 +216,7 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -268,7 +216,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* start of extended comment? */ /* start of extended comment? */
else if (line[i] == '/' && line[i + thislen] == '*') else if (line[i] == '/' && line[i + thislen] == '*')
{ {
xcomment = &line[i]; xcomment = true;
ADVANCE_1; ADVANCE_1;
} }
...@@ -287,8 +235,45 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -287,8 +235,45 @@ MainLoop(PsqlSettings *pset, FILE *source)
else if (line[i] == ')' && paren_level > 0) else if (line[i] == ')' && paren_level > 0)
paren_level--; paren_level--;
/* 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]!=':')
)
{
size_t in_length,
out_length;
const char *value;
char *new;
char after; /* the character after the variable name
will be temporarily overwritten */
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);
out_length = strlen(value);
new = malloc(len + out_length - (1 + in_length) + 1);
if (!new)
{
perror("malloc");
exit(EXIT_FAILURE);
}
sprintf(new, "%.*s%s%c", i, line, value, after);
if (after)
strcat(new, line + i + 1 + in_length + 1);
free(line);
line = new;
continue; /* reparse the just substituted */
}
/* semicolon? then send query */ /* semicolon? then send query */
else if (line[i] == ';' && !was_bslash && paren_level == 0) else if (line[i] == ';' && !was_bslash)
{ {
line[i] = '\0'; line[i] = '\0';
/* is there anything else on the line? */ /* is there anything else on the line? */
...@@ -312,6 +297,15 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -312,6 +297,15 @@ MainLoop(PsqlSettings *pset, FILE *source)
query_start = i + thislen; query_start = i + thislen;
} }
/* if you have a burning need to send a semicolon or colon to
the backend ... */
else if (was_bslash && (line[i] == ';' || line[i] == ':'))
{
/* remove the backslash */
memmove(line + i - prevlen, line + i, len - i + 1);
len--;
}
/* backslash command */ /* backslash command */
else if (was_bslash) else if (was_bslash)
{ {
...@@ -355,7 +349,13 @@ MainLoop(PsqlSettings *pset, FILE *source) ...@@ -355,7 +349,13 @@ MainLoop(PsqlSettings *pset, FILE *source)
else else
break; break;
} }
}
/* stop the script after error */
if (!success && die_on_error)
break;
} /* for (line) */
if (!success && die_on_error && !pset->cur_cmd_interactive) if (!success && die_on_error && !pset->cur_cmd_interactive)
......
...@@ -30,8 +30,8 @@ ...@@ -30,8 +30,8 @@
static void static void
print_unaligned_text(const char *title, const char * const * headers, print_unaligned_text(const char *title, const char * const * headers,
const char * const * cells, const char * const * footers, const char * const * cells, const char * const * footers,
const char *opt_fieldsep, bool opt_barebones, const char *opt_fieldsep, bool opt_barebones,
FILE *fout) FILE *fout)
{ {
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned int i; unsigned int i;
...@@ -83,8 +83,8 @@ print_unaligned_text(const char *title, const char * const * headers, ...@@ -83,8 +83,8 @@ print_unaligned_text(const char *title, const char * const * headers,
static void static void
print_unaligned_vertical(const char *title, const char * const * headers, print_unaligned_vertical(const char *title, const char * const * headers,
const char * const * cells, const char * const * footers, const char * const * cells, const char * const * footers,
const char *opt_fieldsep, bool opt_barebones, const char *opt_fieldsep, bool opt_barebones,
FILE *fout) FILE *fout)
{ {
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned int i; unsigned int i;
...@@ -172,7 +172,7 @@ static void ...@@ -172,7 +172,7 @@ static void
print_aligned_text(const char *title, const char * const * headers, print_aligned_text(const char *title, const char * const * headers,
const char * const * cells, const char * const * footers, const char * const * cells, const char * const * footers,
const char *opt_align, bool opt_barebones, unsigned short int opt_border, const char *opt_align, bool opt_barebones, unsigned short int opt_border,
FILE *fout) FILE *fout)
{ {
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned int i, unsigned int i,
...@@ -313,8 +313,8 @@ print_aligned_text(const char *title, const char * const * headers, ...@@ -313,8 +313,8 @@ print_aligned_text(const char *title, const char * const * headers,
static void static void
print_aligned_vertical(const char *title, const char * const * headers, print_aligned_vertical(const char *title, const char * const * headers,
const char * const * cells, const char * const * footers, const char * const * cells, const char * const * footers,
bool opt_barebones, unsigned short int opt_border, bool opt_barebones, unsigned short int opt_border,
FILE *fout) FILE *fout)
{ {
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned int record = 1; unsigned int record = 1;
...@@ -371,11 +371,10 @@ print_aligned_vertical(const char *title, const char * const * headers, ...@@ -371,11 +371,10 @@ print_aligned_vertical(const char *title, const char * const * headers,
{ {
if (!opt_barebones) if (!opt_barebones)
{ {
char *div_copy = strdup(divider);
char *record_str = malloc(32); char *record_str = malloc(32);
size_t record_str_len; size_t record_str_len;
if (!div_copy || !record_str) if (!record_str)
{ {
perror("malloc"); perror("malloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
...@@ -386,29 +385,32 @@ print_aligned_vertical(const char *title, const char * const * headers, ...@@ -386,29 +385,32 @@ print_aligned_vertical(const char *title, const char * const * headers,
else else
sprintf(record_str, "[ RECORD %d ]", record++); sprintf(record_str, "[ RECORD %d ]", record++);
record_str_len = strlen(record_str); record_str_len = strlen(record_str);
if (record_str_len + opt_border > strlen(div_copy))
{ if (record_str_len + opt_border > strlen(divider))
void *new; fprintf(fout, "%.*s%s\n", opt_border, divider, record_str);
else
new = realloc(div_copy, record_str_len + opt_border); {
if (!new) char *div_copy = strdup(divider);
{
perror("realloc"); if (!div_copy) {
exit(EXIT_FAILURE); perror("malloc");
} exit(EXIT_FAILURE);
div_copy = new; }
}
strncpy(div_copy + opt_border, record_str, record_str_len); strncpy(div_copy + opt_border, record_str, record_str_len);
fprintf(fout, "%s\n", div_copy); fprintf(fout, "%s\n", div_copy);
free(div_copy);
}
free(record_str); free(record_str);
free(div_copy);
} }
else if (i != 0 && opt_border < 2) else if (i != 0 || opt_border == 2)
fprintf(fout, "%s\n", divider); fprintf(fout, "%s\n", divider);
} }
if (opt_border == 2) if (opt_border == 2)
fputs("| ", fout); fputs("| ", fout);
fprintf(fout, "%-*s", hwidth, headers[i % col_count]); fprintf(fout, "%-*s", hwidth, headers[i % col_count]);
if (opt_border > 0) if (opt_border > 0)
fputs(" | ", fout); fputs(" | ", fout);
else else
...@@ -479,7 +481,7 @@ print_html_text(const char *title, const char * const * headers, ...@@ -479,7 +481,7 @@ print_html_text(const char *title, const char * const * headers,
const char * const * cells, const char * const * footers, const char * const * cells, const char * const * footers,
const char *opt_align, bool opt_barebones, unsigned short int opt_border, const char *opt_align, bool opt_barebones, unsigned short int opt_border,
const char *opt_table_attr, const char *opt_table_attr,
FILE *fout) FILE *fout)
{ {
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned int i; unsigned int i;
...@@ -661,7 +663,7 @@ static void ...@@ -661,7 +663,7 @@ static void
print_latex_text(const char *title, const char * const * headers, print_latex_text(const char *title, const char * const * headers,
const char * const * cells, const char * const * footers, const char * const * cells, const char * const * footers,
const char *opt_align, bool opt_barebones, unsigned short int opt_border, const char *opt_align, bool opt_barebones, unsigned short int opt_border,
FILE *fout) FILE *fout)
{ {
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned int i; unsigned int i;
...@@ -757,7 +759,7 @@ static void ...@@ -757,7 +759,7 @@ static void
print_latex_vertical(const char *title, const char * const * headers, print_latex_vertical(const char *title, const char * const * headers,
const char * const * cells, const char * const * footers, const char * const * cells, const char * const * footers,
const char *opt_align, bool opt_barebones, unsigned short int opt_border, const char *opt_align, bool opt_barebones, unsigned short int opt_border,
FILE *fout) FILE *fout)
{ {
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned int i; unsigned int i;
...@@ -836,7 +838,7 @@ print_latex_vertical(const char *title, const char * const * headers, ...@@ -836,7 +838,7 @@ print_latex_vertical(const char *title, const char * const * headers,
/********************************/ /********************************/
/* Public functions */ /* Public functions */
/********************************/ /********************************/
...@@ -845,8 +847,8 @@ printTable(const char *title, ...@@ -845,8 +847,8 @@ printTable(const char *title,
const char * const * headers, const char * const * headers,
const char * const * cells, const char * const * cells,
const char * const * footers, const char * const * footers,
const char *align, const char *align,
const printTableOpt * opt, FILE *fout) const printTableOpt * opt, FILE *fout)
{ {
const char *default_footer[] = {NULL}; const char *default_footer[] = {NULL};
unsigned short int border = opt->border; unsigned short int border = opt->border;
...@@ -968,8 +970,8 @@ printQuery(const PGresult *result, const printQueryOpt * opt, FILE *fout) ...@@ -968,8 +970,8 @@ printQuery(const PGresult *result, const printQueryOpt * opt, FILE *fout)
int nfields; int nfields;
const char **headers; const char **headers;
const char **cells; const char **cells;
char **footers; char **footers;
char *align; char *align;
int i; int i;
/* extract headers */ /* extract headers */
......
...@@ -46,8 +46,8 @@ typedef struct _printTableOpt ...@@ -46,8 +46,8 @@ typedef struct _printTableOpt
*/ */
void printTable(const char *title, const char * const * headers, void printTable(const char *title, const char * const * headers,
const char * const * cells, const char * const * footers, const char * const * cells, const char * const * footers,
const char *align, const char *align,
const printTableOpt * opt, FILE *fout); const printTableOpt * opt, FILE *fout);
......
...@@ -85,7 +85,7 @@ get_prompt(PsqlSettings *pset, promptStatus_t status) ...@@ -85,7 +85,7 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
p && *p && strlen(destination) < MAX_PROMPT_SIZE; p && *p && strlen(destination) < MAX_PROMPT_SIZE;
p++) p++)
{ {
MemSet(buf, 0, MAX_PROMPT_SIZE + 1); memset(buf, 0, MAX_PROMPT_SIZE + 1);
if (esc) if (esc)
{ {
switch (*p) switch (*p)
......
#ifndef SETTINGS_H #ifndef SETTINGS_H
#define SETTINGS_H #define SETTINGS_H
#include <config.h>
#include <c.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <libpq-fe.h> #include <libpq-fe.h>
#include <c.h> #include <postgres_ext.h>
#include "variables.h" #include "variables.h"
#include "print.h" #include "print.h"
...@@ -41,6 +43,8 @@ typedef struct _psqlSettings ...@@ -41,6 +43,8 @@ typedef struct _psqlSettings
bool has_client_encoding; /* was PGCLIENTENCODING set on bool has_client_encoding; /* was PGCLIENTENCODING set on
* startup? */ * startup? */
Oid lastOid; /* saves oid from insert command
because people want it so badly */
} PsqlSettings; } PsqlSettings;
......
...@@ -88,7 +88,7 @@ main(int argc, char **argv) ...@@ -88,7 +88,7 @@ main(int argc, char **argv)
char *password = NULL; char *password = NULL;
bool need_pass; bool need_pass;
MemSet(&settings, 0, sizeof settings); memset(&settings, 0, sizeof settings);
settings.cur_cmd_source = stdin; settings.cur_cmd_source = stdin;
settings.cur_cmd_interactive = false; settings.cur_cmd_interactive = false;
...@@ -161,7 +161,7 @@ main(int argc, char **argv) ...@@ -161,7 +161,7 @@ main(int argc, char **argv)
if (options.action == ACT_LIST_DB) if (options.action == ACT_LIST_DB)
{ {
int success = listAllDbs(&settings); int success = listAllDbs(&settings, false);
PQfinish(settings.db); PQfinish(settings.db);
exit(!success); exit(!success);
...@@ -179,15 +179,15 @@ main(int argc, char **argv) ...@@ -179,15 +179,15 @@ main(int argc, char **argv)
{ {
puts("Welcome to psql, the PostgreSQL interactive terminal.\n\n" puts("Welcome to psql, the PostgreSQL interactive terminal.\n\n"
"Type: \\copyright for distribution terms\n" "Type: \\copyright for distribution terms\n"
" \\h for help with SQL commands\n" " \\h for help with SQL commands\n"
" \\? for help on internal slash commands\n" " \\? for help on internal slash commands\n"
" \\g or terminate with semicolon to execute query\n" " \\g or terminate with semicolon to execute query\n"
" \\q to quit\n"); " \\q to quit\n");
} }
process_psqlrc(&settings); process_psqlrc(&settings);
initializeInput(options.no_readline ? 0 : 1); initializeInput(options.no_readline ? 0 : 1, &settings);
/* Now find something to do */ /* Now find something to do */
...@@ -270,7 +270,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op ...@@ -270,7 +270,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op
extern int optind; extern int optind;
int c; int c;
MemSet(options, 0, sizeof *options); memset(options, 0, sizeof *options);
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
while ((c = getopt_long(argc, argv, "Ac:d:eEf:F:lh:Hno:p:P:qsStT:uU:v:VWx?", long_options, &optindex)) != -1) while ((c = getopt_long(argc, argv, "Ac:d:eEf:F:lh:Hno:p:P:qsStT:uU:v:VWx?", long_options, &optindex)) != -1)
...@@ -516,8 +516,8 @@ showVersion(PsqlSettings *pset) ...@@ -516,8 +516,8 @@ showVersion(PsqlSettings *pset)
/* get backend version */ /* get backend version */
if (pset->db && PQstatus(pset->db) == CONNECTION_OK) { if (pset->db && PQstatus(pset->db) == CONNECTION_OK) {
res = PSQLexec(pset, "SELECT version()"); res = PSQLexec(pset, "SELECT version()");
if (PQresultStatus(res) == PGRES_TUPLES_OK) if (PQresultStatus(res) == PGRES_TUPLES_OK)
versionstr = PQgetvalue(res, 0, 0); versionstr = PQgetvalue(res, 0, 0);
} }
...@@ -566,5 +566,5 @@ showVersion(PsqlSettings *pset) ...@@ -566,5 +566,5 @@ showVersion(PsqlSettings *pset)
"distribution."); "distribution.");
if (res) if (res)
PQclear(res); PQclear(res);
} }
This diff is collapsed.
#ifndef TAB_COMPLETE_H
#define TAB_COMPLETE_H
#include <libpq-fe.h>
void initialize_readline(PGconn ** conn);
#endif
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
#define VARIABLES_H #define VARIABLES_H
#include <c.h> #include <c.h>
#define VALID_VARIABLE_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_" #define VALID_VARIABLE_CHARS "abcdefghijklmnopqrstuvwxyz"\
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_"
struct _variable struct _variable
{ {
......
# Makefile for Microsoft Visual C++ 5.0 (or compat)
!IF "$(OS)" == "Windows_NT"
NULL=
!ELSE
NULL=nul
!ENDIF
CPP=cl.exe
OUTDIR=.\Release
INTDIR=.\Release
# Begin Custom Macros
OutDir=.\Release
# End Custom Macros
ALL : "$(OUTDIR)\psql.exe"
CLEAN :
-@erase "$(INTDIR)\psql.obj"
-@erase "$(INTDIR)\stringutils.obj"
-@erase "$(INTDIR)\getopt.obj"
-@erase "$(INTDIR)\vc50.idb"
-@erase "$(OUTDIR)\psql.exe"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D\
"_MBCS" /Fp"$(INTDIR)\psql.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c \
/I ..\..\include /I ..\..\interfaces\libpq /D "HAVE_STRDUP" /D "BLCKSZ=8192"
!IFDEF MULTIBYTE
!IFNDEF MBFLAGS
MBFLAGS="-DMULTIBYTE=$(MULTIBYTE)"
!ENDIF
CPP_PROJ=$(MBFLAGS) $(CPP_PROJ)
!ENDIF
CPP_OBJS=.\Release/
CPP_SBRS=.
LINK32=link.exe
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
odbccp32.lib wsock32.lib /nologo /subsystem:console /incremental:no\
/pdb:"$(OUTDIR)\psql.pdb" /machine:I386 /out:"$(OUTDIR)\psql.exe"
LINK32_OBJS= \
"$(INTDIR)\psql.obj" \
"$(INTDIR)\stringutils.obj" \
"$(INTDIR)\getopt.obj" \
"..\..\interfaces\libpq\Release\libpqdll.lib"
"$(OUTDIR)\psql.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
"$(OUTDIR)\getopt.obj" : "$(OUTDIR)" ..\..\utils\getopt.c
$(CPP) @<<
$(CPP_PROJ) ..\..\utils\getopt.c
<<
.c{$(CPP_OBJS)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cpp{$(CPP_OBJS)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
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