From 3c87e42a8ff7c0be9a85be0f71e974ec5205f4d6 Mon Sep 17 00:00:00 2001 From: Ayush Tiwari Date: Mon, 20 Apr 2026 11:16:36 +0530 Subject: [PATCH v2] Reject ENCODING option for COPY TO FORMAT JSON COPY TO FORMAT JSON silently accepted the ENCODING option but did not perform any encoding conversion. CopyToJsonOneRow() sends the output of composite_to_json() directly via CopySendData() without calling pg_server_to_any(), unlike the text and CSV paths which correctly convert when need_transcoding is true. This meant COPY ... TO ... WITH (FORMAT json, ENCODING 'LATIN1') on a UTF-8 server silently produced UTF-8 output instead of LATIN1. Reject the option for now, consistent with how DELIMITER, NULL, DEFAULT, and HEADER are already rejected for JSON mode. Proper encoding conversion support can be added in a future release. Introduced by 7dadd38cda9 (json format for COPY TO). --- src/backend/commands/copy.c | 11 +++++++++++ src/test/regress/expected/copy.out | 2 ++ src/test/regress/sql/copy.sql | 1 + 3 files changed, 14 insertions(+) diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 003b70852bb..967ee3b0f94 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -887,6 +887,17 @@ ProcessCopyOptions(ParseState *pstate, ? errmsg("cannot specify %s in BINARY mode", "HEADER") : errmsg("cannot specify %s in JSON mode", "HEADER")); + /* + * Reject ENCODING for JSON format. JSON output is produced as a whole + * by composite_to_json(), so the per-attribute encoding conversion done + * for text and CSV output is not applied. + */ + if (opts_out->file_encoding >= 0 && + opts_out->format == COPY_FORMAT_JSON) + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot specify %s in JSON mode", "ENCODING")); + /* Check quote */ if (opts_out->format != COPY_FORMAT_CSV && opts_out->quote != NULL) ereport(ERROR, diff --git a/src/test/regress/expected/copy.out b/src/test/regress/expected/copy.out index 1714faab39c..99c53c462c4 100644 --- a/src/test/regress/expected/copy.out +++ b/src/test/regress/expected/copy.out @@ -135,6 +135,8 @@ LINE 1: copy copytest to stdout (format json, on_error ignore); ^ copy copytest to stdout (format json, reject_limit 1); ERROR: COPY REJECT_LIMIT requires ON_ERROR to be set to IGNORE +copy copytest to stdout (format json, encoding 'LATIN1'); +ERROR: cannot specify ENCODING in JSON mode copy copytest from stdin(format json); ERROR: COPY FORMAT JSON is not supported for COPY FROM -- all of the above should yield error diff --git a/src/test/regress/sql/copy.sql b/src/test/regress/sql/copy.sql index eaad290b257..d30900a3ef2 100644 --- a/src/test/regress/sql/copy.sql +++ b/src/test/regress/sql/copy.sql @@ -105,6 +105,7 @@ copy copytest to stdout (format json, force_not_null *); copy copytest to stdout (format json, force_null *); copy copytest to stdout (format json, on_error ignore); copy copytest to stdout (format json, reject_limit 1); +copy copytest to stdout (format json, encoding 'LATIN1'); copy copytest from stdin(format json); -- all of the above should yield error -- 2.34.1