1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-29 10:41:53 +03:00

Implement a psql command "\ef" to edit the definition of a function.

In support of that, create a backend function pg_get_functiondef().
The psql command is functional but maybe a bit rough around the edges...

Abhijit Menon-Sen
This commit is contained in:
Tom Lane
2008-09-06 00:01:25 +00:00
parent 2cdcf459ba
commit 2c863ca818
7 changed files with 407 additions and 59 deletions

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.193 2008/08/16 00:16:56 momjian Exp $
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.194 2008/09/06 00:01:24 tgl Exp $
*/
#include "postgres_fe.h"
#include "command.h"
@ -56,9 +56,12 @@
static backslashResult exec_command(const char *cmd,
PsqlScanState scan_state,
PQExpBuffer query_buf);
static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
static bool do_edit(const char *filename_arg, PQExpBuffer query_buf,
bool *edited);
static bool do_connect(char *dbname, char *user, char *host, char *port);
static bool do_shell(const char *command);
static bool lookup_function_oid(PGconn *conn, const char *desc, Oid *foid);
static bool get_create_function_cmd(PGconn *conn, Oid oid, PQExpBuffer buf);
#ifdef USE_SSL
static void printSSLInfo(void);
@ -444,11 +447,64 @@ exec_command(const char *cmd,
expand_tilde(&fname);
if (fname)
canonicalize_path(fname);
status = do_edit(fname, query_buf) ? PSQL_CMD_NEWEDIT : PSQL_CMD_ERROR;
if (do_edit(fname, query_buf, NULL))
status = PSQL_CMD_NEWEDIT;
else
status = PSQL_CMD_ERROR;
free(fname);
}
}
/*
* \ef -- edit the named function in $EDITOR.
*/
else if (strcmp(cmd, "ef") == 0)
{
char *func;
Oid foid;
func = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, true);
if (!func)
{
psql_error("no function name specified\n");
status = PSQL_CMD_ERROR;
}
else if (!lookup_function_oid(pset.db, func, &foid))
{
psql_error(PQerrorMessage(pset.db));
status = PSQL_CMD_ERROR;
}
else if (!query_buf)
{
psql_error("no query buffer\n");
status = PSQL_CMD_ERROR;
}
else if (!get_create_function_cmd(pset.db, foid, query_buf))
{
psql_error(PQerrorMessage(pset.db));
status = PSQL_CMD_ERROR;
}
else
{
bool edited = false;
if (!do_edit(0, query_buf, &edited))
{
status = PSQL_CMD_ERROR;
}
else if (!edited)
{
printf("No changes\n");
}
else
{
status = PSQL_CMD_NEWEDIT;
}
}
if (func)
free(func);
}
/* \echo and \qecho */
else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0)
{
@ -1410,7 +1466,7 @@ editFile(const char *fname)
/* call this one */
static bool
do_edit(const char *filename_arg, PQExpBuffer query_buf)
do_edit(const char *filename_arg, PQExpBuffer query_buf, bool *edited)
{
char fnametmp[MAXPGPATH];
FILE *stream = NULL;
@ -1532,10 +1588,13 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf)
psql_error("%s: %s\n", fname, strerror(errno));
error = true;
}
else if (edited)
{
*edited = true;
}
fclose(stream);
}
}
/* remove temp file */
@ -1912,3 +1971,66 @@ do_shell(const char *command)
}
return true;
}
/*
* This function takes a function description, e.g. "x" or "x(int)", and
* issues a query on the given connection to retrieve the function's OID
* using a cast to regproc or regprocedure (as appropriate). The result,
* if there is one, is returned at *foid. Note that we'll fail if the
* function doesn't exist OR if there are multiple matching candidates
* OR if there's something syntactically wrong with the function description;
* unfortunately it can be hard to tell the difference.
*/
static bool
lookup_function_oid(PGconn *conn, const char *desc, Oid *foid)
{
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
result = false;
PQclear(res);
destroyPQExpBuffer(query);
return result;
}
/*
* Fetches the "CREATE OR REPLACE FUNCTION ..." command that describes the
* function with the given OID. If successful, the result is stored in buf.
*/
static bool
get_create_function_cmd(PGconn *conn, Oid oid, PQExpBuffer buf)
{
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
result = false;
PQclear(res);
destroyPQExpBuffer(query);
return result;
}