diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 74d46183e5..db314c326f 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -3315,6 +3315,15 @@ testdb=> INSERT INTO my_table VALUES (:'content');
+
+ %l
+
+
+ The line number inside the current statement, starting from 1>.
+
+
+
+
%digits
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c
index 4b749154ad..90f4a24fa5 100644
--- a/src/bin/psql/copy.c
+++ b/src/bin/psql/copy.c
@@ -517,8 +517,8 @@ bool
handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
{
bool OK;
- const char *prompt;
char buf[COPYBUFSIZ];
+ bool showprompt = false;
/*
* Establish longjmp destination for exiting from wait-for-input. (This is
@@ -540,21 +540,20 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
/* Prompt if interactive input */
if (isatty(fileno(copystream)))
{
+ showprompt = true;
if (!pset.quiet)
puts(_("Enter data to be copied followed by a newline.\n"
"End with a backslash and a period on a line by itself."));
- prompt = get_prompt(PROMPT_COPY);
}
- else
- prompt = NULL;
OK = true;
if (isbinary)
{
/* interactive input probably silly, but give one prompt anyway */
- if (prompt)
+ if (showprompt)
{
+ const char *prompt = get_prompt(PROMPT_COPY);
fputs(prompt, stdout);
fflush(stdout);
}
@@ -589,8 +588,9 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
bool firstload;
bool linedone;
- if (prompt)
+ if (showprompt)
{
+ const char *prompt = get_prompt(PROMPT_COPY);
fputs(prompt, stdout);
fflush(stdout);
}
@@ -650,7 +650,10 @@ handleCopyIn(PGconn *conn, FILE *copystream, bool isbinary, PGresult **res)
}
if (copystream == pset.cur_cmd_source)
+ {
pset.lineno++;
+ pset.stmt_lineno++;
+ }
}
}
diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c
index c3aff208bf..98211dcb2a 100644
--- a/src/bin/psql/mainloop.c
+++ b/src/bin/psql/mainloop.c
@@ -58,6 +58,7 @@ MainLoop(FILE *source)
pset.cur_cmd_source = source;
pset.cur_cmd_interactive = ((source == stdin) && !pset.notty);
pset.lineno = 0;
+ pset.stmt_lineno = 1;
/* Create working state */
scan_state = psql_scan_create();
@@ -110,6 +111,7 @@ MainLoop(FILE *source)
count_eof = 0;
slashCmdStatus = PSQL_CMD_UNKNOWN;
prompt_status = PROMPT_READY;
+ pset.stmt_lineno = 1;
cancel_pressed = false;
if (pset.cur_cmd_interactive)
@@ -225,7 +227,10 @@ MainLoop(FILE *source)
{
PsqlScanResult scan_result;
promptStatus_t prompt_tmp = prompt_status;
+ size_t pos_in_query;
+ char *tmp_line;
+ pos_in_query = query_buf->len;
scan_result = psql_scan(scan_state, query_buf, &prompt_tmp);
prompt_status = prompt_tmp;
@@ -235,6 +240,22 @@ MainLoop(FILE *source)
exit(EXIT_FAILURE);
}
+ /*
+ * Increase statement line number counter for each linebreak added
+ * to the query buffer by the last psql_scan() call. There only
+ * will be ones to add when navigating to a statement in
+ * readline's history containing newlines.
+ */
+ tmp_line = query_buf->data + pos_in_query;
+ while (*tmp_line != '\0')
+ {
+ if (*(tmp_line++) == '\n')
+ pset.stmt_lineno++;
+ }
+
+ if (scan_result == PSCAN_EOL)
+ pset.stmt_lineno++;
+
/*
* Send command if semicolon found, or if end of line and we're in
* single-line mode.
@@ -256,6 +277,7 @@ MainLoop(FILE *source)
/* execute query */
success = SendQuery(query_buf->data);
slashCmdStatus = success ? PSQL_CMD_SEND : PSQL_CMD_ERROR;
+ pset.stmt_lineno = 1;
/* transfer query to previous_buf by pointer-swapping */
{
@@ -303,6 +325,7 @@ MainLoop(FILE *source)
query_buf : previous_buf);
success = slashCmdStatus != PSQL_CMD_ERROR;
+ pset.stmt_lineno = 1;
if ((slashCmdStatus == PSQL_CMD_SEND || slashCmdStatus == PSQL_CMD_NEWEDIT) &&
query_buf->len == 0)
diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c
index 26fca04756..f2db9a97bc 100644
--- a/src/bin/psql/prompt.c
+++ b/src/bin/psql/prompt.c
@@ -44,6 +44,7 @@
* in prompt2 -, *, ', or ";
* in prompt3 nothing
* %x - transaction status: empty, *, !, ? (unknown or no connection)
+ * %l - The line number inside the current statement, starting from 1.
* %? - the error code of the last query (not yet implemented)
* %% - a percent sign
*
@@ -229,6 +230,10 @@ get_prompt(promptStatus_t status)
}
break;
+ case 'l':
+ snprintf(buf, sizeof(buf), UINT64_FORMAT, pset.stmt_lineno);
+ break;
+
case '?':
/* not here yet */
break;
diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h
index 453d6c889d..ef24a4ef98 100644
--- a/src/bin/psql/settings.h
+++ b/src/bin/psql/settings.h
@@ -88,6 +88,7 @@ typedef struct _psqlSettings
const char *progname; /* in case you renamed psql */
char *inputfile; /* file being currently processed, if any */
uint64 lineno; /* also for error reporting */
+ uint64 stmt_lineno; /* line number inside the current statement */
bool timing; /* enable timing of all queries */