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);
signature.asc
Description: PGP signature