Hello.

Sometimes it's useful to log content of files used in COPY ... TO ... and
COPY ... FROM ... queries. Unfortunately PostgreSQL doesn't allow to do
it, even if log_statement='all'. Suggested patch fixes this.

Log example:

```
LOG:  statement: create table test (k int, v text);
LOG:  statement: insert into test values (111, 'aaa'), (222, 'bbb');
LOG:  statement: copy test to '/tmp/copy.txt';
LOG:  statement: 111    aaa
LOG:  statement: 222    bbb
LOG:  statement: delete from test;
LOG:  statement: copy test from '/tmp/copy.txt';
LOG:  statement: 111    aaa
LOG:  statement: 222    bbb
```
-- 
Best regards,
Aleksander Alekseev
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 5947e72..82b3a18 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -331,6 +331,38 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 
 
 /*
+ * Logs file content during COPY ... FROM / COPY ... TO execution if
+ * log_statement = 'all'.
+ */
+static void
+CopyLogStatement(const char* str, bool flush)
+{
+	static StringInfo logString = NULL;
+
+	if(log_statement != LOGSTMT_ALL)
+		return;
+
+	if(logString == NULL)
+	{
+		MemoryContext oldctx = MemoryContextSwitchTo(TopMemoryContext);
+		logString = makeStringInfo();
+		MemoryContextSwitchTo(oldctx);
+	}
+
+	appendStringInfoString(logString, str);
+
+	if(flush)
+	{
+		ereport(LOG,
+				(errmsg("statement: %s", logString->data),
+				 errhidestmt(true),
+				 errhidecontext(true)));
+
+		resetStringInfo(logString);
+	}
+}
+
+/*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
  */
@@ -2045,14 +2077,20 @@ CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls)
 		if (!cstate->binary)
 		{
 			if (need_delim)
+			{
 				CopySendChar(cstate, cstate->delim[0]);
+				CopyLogStatement(cstate->delim, false);
+			}
 			need_delim = true;
 		}
 
 		if (isnull)
 		{
 			if (!cstate->binary)
+			{
 				CopySendString(cstate, cstate->null_print_client);
+				CopyLogStatement(cstate->null_print_client, false);
+			}
 			else
 				CopySendInt32(cstate, -1);
 		}
@@ -2062,6 +2100,9 @@ CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls)
 			{
 				string = OutputFunctionCall(&out_functions[attnum - 1],
 											value);
+
+				CopyLogStatement(string, false);
+
 				if (cstate->csv_mode)
 					CopyAttributeOutCSV(cstate, string,
 										cstate->force_quote_flags[attnum - 1],
@@ -2083,6 +2124,7 @@ CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls)
 	}
 
 	CopySendEndOfRow(cstate);
+	CopyLogStatement("", true);
 
 	MemoryContextSwitchTo(oldcontext);
 }
@@ -2914,6 +2956,8 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	if (done && cstate->line_buf.len == 0)
 		return false;
 
+	CopyLogStatement(cstate->line_buf.data, true);
+
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
 		fldct = CopyReadAttributesCSV(cstate);

Attachment: signature.asc
Description: PGP signature

Reply via email to