From 600b873d59529de3ded5da8f92eefe957bdd3df8 Mon Sep 17 00:00:00 2001 From: tgl Date: Sat, 6 Sep 2008 20:18:08 +0000 Subject: [PATCH] Adjust psql's new \ef command to present an empty CREATE FUNCTION template for editing if no function name is specified. This seems a much cleaner way to offer that functionality than the original patch had. In passing, de-clutter the error displays that are given for a bogus function-name argument, and standardize on "$function$" as the default delimiter for the function body. (The original coding would use the shortest possible dollar-quote delimiter, which seems to create unnecessarily high risk of later conflicts with the user-modified function body.) --- doc/src/sgml/ref/psql-ref.sgml | 9 +++- src/backend/utils/adt/ruleutils.c | 10 +++- src/bin/psql/command.c | 104 ++++++++++++++++++++++++++------------ 3 files changed, 88 insertions(+), 35 deletions(-) diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 5a4ae240bb..b5acde54fc 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1161,7 +1161,7 @@ testdb=> - \edit (or \e) [ filename ] + \edit (or \e) filename @@ -1196,7 +1196,7 @@ testdb=> - \ef function_description + \ef function_description @@ -1214,6 +1214,11 @@ testdb=> The argument types must be given if there is more than one function of the same name. + + + If no function is specified, a blank CREATE FUNCTION + template is presented for editing. + diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index a1686379e8..2da3d3aa21 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -1543,9 +1543,15 @@ pg_get_functiondef(PG_FUNCTION_ARGS) elog(ERROR, "null prosrc"); prosrc = TextDatumGetCString(tmp); - /* We always use dollar quoting. Figure out a suitable delimiter. */ + /* + * We always use dollar quoting. Figure out a suitable delimiter. + * + * Since the user is likely to be editing the function body string, + * we shouldn't use a short delimiter that he might easily create a + * conflict with. Hence prefer "$function$", but extend if needed. + */ initStringInfo(&dq); - appendStringInfoChar(&dq, '$'); + appendStringInfoString(&dq, "$function"); while (strstr(prosrc, dq.data) != NULL) appendStringInfoChar(&dq, 'x'); appendStringInfoChar(&dq, '$'); diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 34344b8dfc..752f361c06 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -62,6 +62,7 @@ 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); +static void minimal_error_message(PGresult *res); #ifdef USE_SSL static void printSSLInfo(void); @@ -433,8 +434,6 @@ exec_command(const char *cmd, */ else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0) { - char *fname; - if (!query_buf) { psql_error("no query buffer\n"); @@ -442,6 +441,8 @@ exec_command(const char *cmd, } else { + char *fname; + fname = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true); expand_tilde(&fname); @@ -456,53 +457,59 @@ exec_command(const char *cmd, } /* - * \ef -- edit the named function in $EDITOR. + * \ef -- edit the named function, or present a blank CREATE FUNCTION + * template if no argument is given */ 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) + 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; + char *func; + Oid foid; - if (!do_edit(0, query_buf, &edited)) + func = psql_scan_slash_option(scan_state, + OT_WHOLE_LINE, NULL, true); + if (!func) { + /* set up an empty command to fill in */ + printfPQExpBuffer(query_buf, + "CREATE FUNCTION ( )\n" + " RETURNS \n" + " LANGUAGE \n" + " -- common options: IMMUTABLE STABLE STRICT SECURITY DEFINER\n" + "AS $function$\n" + "\n$function$\n"); + } + else if (!lookup_function_oid(pset.db, func, &foid)) + { + /* error already reported */ status = PSQL_CMD_ERROR; } - else if (!edited) + else if (!get_create_function_cmd(pset.db, foid, query_buf)) { - printf("No changes\n"); + /* error already reported */ + status = PSQL_CMD_ERROR; } + if (func) + free(func); + } + + if (status != PSQL_CMD_ERROR) + { + bool edited = false; + + if (!do_edit(0, query_buf, &edited)) + status = PSQL_CMD_ERROR; + else if (!edited) + puts(_("No changes.")); else - { status = PSQL_CMD_NEWEDIT; - } } - if (func) - free(func); } /* \echo and \qecho */ @@ -1998,7 +2005,10 @@ lookup_function_oid(PGconn *conn, const char *desc, Oid *foid) 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); @@ -2027,10 +2037,42 @@ get_create_function_cmd(PGconn *conn, Oid oid, PQExpBuffer buf) appendPQExpBufferStr(buf, PQgetvalue(res, 0, 0)); } else + { + minimal_error_message(res); result = false; + } PQclear(res); destroyPQExpBuffer(query); return result; } + +/* + * Report just the primary error; this is to avoid cluttering the output + * with, for instance, a redisplay of the internally generated query + */ +static void +minimal_error_message(PGresult *res) +{ + PQExpBuffer msg; + const char *fld; + + msg = createPQExpBuffer(); + + fld = PQresultErrorField(res, PG_DIAG_SEVERITY); + if (fld) + printfPQExpBuffer(msg, "%s: ", fld); + else + printfPQExpBuffer(msg, "ERROR: "); + fld = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY); + if (fld) + appendPQExpBufferStr(msg, fld); + else + appendPQExpBufferStr(msg, "(not available)"); + appendPQExpBufferStr(msg, "\n"); + + psql_error(msg->data); + + destroyPQExpBuffer(msg); +} -- 2.11.4.GIT