Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wKXu3-0017Sf-0Z for pgsql-hackers@arkaria.postgresql.org; Wed, 06 May 2026 08:46:47 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wKXu2-00Fsyk-07 for pgsql-hackers@arkaria.postgresql.org; Wed, 06 May 2026 08:46:46 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wKXu1-00Fsyc-2Q for pgsql-hackers@lists.postgresql.org; Wed, 06 May 2026 08:46:45 +0000 Received: from mail-pj1-x102e.google.com ([2607:f8b0:4864:20::102e]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wKXtz-00000000SYx-1TM6 for pgsql-hackers@lists.postgresql.org; Wed, 06 May 2026 08:46:44 +0000 Received: by mail-pj1-x102e.google.com with SMTP id 98e67ed59e1d1-365212191f6so2832211a91.3 for ; Wed, 06 May 2026 01:46:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778057203; x=1778662003; darn=lists.postgresql.org; h=content-transfer-encoding:in-reply-to:from:references:to:subject :user-agent:mime-version:date:message-id:from:to:cc:subject:date :message-id:reply-to; bh=m+S2WJ1I5CkpQImI11uWh3yWuyIpUOa33qF9FSBUdR0=; b=sanGHCxFW4qpVXWO4b2SQ9vCL5LjWrBt0AxaxZoUQDkRUedegLCDGySL/BzXps+/r1 UPs0DYJEPJvEPqRybjZtHw+jgmV6zkrcUoMBnXvvZje5dbq6bw1hmW9scQO2J+H1Pyni LZ6h0FZfoMdz6B3GbzfCvIA85rk3agtTsyUVx+M2CcydNHL5D5unwGfmeiZnoxzRFjYy TtCxX4mq2JMvsXWlwP9f2Vb0KQ7Em4k75czMw+f2v2hrJAJDQ/SClSsDpbvosxGtN2Mi vZsDlAgZnKsU9y3UF5cipWf+RT/NQKeNr1olNMpYtxm6fMxY9TtITjllNDTvSfmSMPfT J4Vw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778057203; x=1778662003; h=content-transfer-encoding:in-reply-to:from:references:to:subject :user-agent:mime-version:date:message-id:x-gm-gg:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=m+S2WJ1I5CkpQImI11uWh3yWuyIpUOa33qF9FSBUdR0=; b=AmFuczaAAGj9Pz1+bdIDvjhh4mE0fLFhg47foZJhW93FO87v9wtf4uGmgpngTiuoiB 3a+75TPISsxfNj4c8SUA/cvPBOMPH5tG9dfP0IPy8o0guuPSr5pkubjR8SpJZoPjYKtS OFL0L43S9VDRjwGjymugit4Ny0Q2Y3pI1b5oIS52q5+vtHj2mh1Jn/ClQ2BsPWWrP4oK lAC4H6RDC3uwAczUt9OPCbzn/tt8LXvgV4NuXqil6i8/TG81hGuJHC2O1P9ZpC5PiKh6 m24M8cTuo8M0/j7jO/Q6bjjrfL+PzOYUn0LqRYF4xghdwIKuz1cCzY4heQT8Z6lQ71Zz tEew== X-Forwarded-Encrypted: i=1; AFNElJ+RBqz31gaHnITG15JsS5g55+IG6XGxnPBBXFfxgLanpZahuSmj5NPWLCyuJPAfwoac/HVzZgykkB+XNZP3@lists.postgresql.org X-Gm-Message-State: AOJu0Ywk5c/n6HvfxKgGiTB5ylJivmDJ899+EGDxNpgk9rDB+Nt+THqr gmXMMDiuQJk57Ac8JK37ywKEqXbayvEhC9ABDOXXj9Z+AaRd9ja8VCM= X-Gm-Gg: AeBDievSpw75cCLJoZqN30gQBLhsgwfMLGYL33I3uyM4DLNJjRa66prR5SM9iJw501m AbHyJWGax3A/0GEUZVygUXRb81WH6iZ8MGo1AKGLLnilgWYDmYIuHNBhzPP8gk5r6/fizFPR0P3 MoDJAXA1yHX9Nt9Je+xoKfzbh3rY7KdSGQhNwnuP0IA/vIcTmEuz0aIjyLsbbJSoP/UDFvuLfds GIEHScWKvb35P4no823EiCGBTMWfWllyB+R4PS9NsHUvUdnjFX2ahNMXN7toJJiphkHJbhHXGow q0WzrbOJW95gvPNWAb4npshldKiBLOQRIoIWOqAcb+rfoWO41hKxB+TIENO+63TlOLYWgBtOW9M 1qIUy25hC+OnWrHVHhuNVuPXc0zL/dOure0Wq8eQ+f4uLh3gEE7XJQ4foxLpxt82IxNqKsPI+he NsqfLiA5gTpZSonBLQqixfxxLQYnWia/KUjl4DBYFXkw== X-Received: by 2002:a17:90a:da8b:b0:362:ef3a:a153 with SMTP id 98e67ed59e1d1-365abcf3b71mr2398994a91.12.1778057202869; Wed, 06 May 2026 01:46:42 -0700 (PDT) Received: from [198.18.0.2] ([50.114.55.223]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-365b0ed8305sm918280a91.3.2026.05.06.01.46.40 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 06 May 2026 01:46:42 -0700 (PDT) Message-ID: <5f99e4a9-efa1-4458-b829-e7a7ff366f08@gmail.com> Date: Wed, 6 May 2026 16:46:33 +0800 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: COPY JSON: use trailing commas in FORCE_ARRAY output To: Chao Li , PostgreSQL Hackers References: From: Alex Guo In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 5/6/26 2:40 PM, Chao Li wrote: > Hi, > > Another issue I found with COPY TO (FORMAT json, FORCE_ARRAY) is that it places the delimiter comma at the beginning of the next line, like this: > ``` > evantest=# copy test_json_copy to stdout with (format json, force_array); > [ > {"id":1,"name":"Alice","is_active":true,"tags":["dev","db"],"created_at":"2026-05-01"} > ,{"id":2,"name":"Bob","is_active":false,"tags":["manager"],"created_at":"2026-05-02"} > ,{"id":3,"name":"Charlie","is_active":null,"tags":null,"created_at":null} > ,{"id":4,"name":"Special Case: \"Quotes\"","is_active":true,"tags":["a","b"],"created_at":"2026-05-04"} > ] > ``` > > I was surprised by the comma placement. It is valid JSON, but it looks quite uncommon. > > For comparison, the existing json_agg() places commas at the end of the line: > ``` > evantest=# select json_agg(t) from (select id, name from test_json_copy) t; > json_agg > ---------------------------------------------- > [{"id":1,"name":"Alice"}, + > {"id":2,"name":"Bob"}, + > {"id":3,"name":"Charlie"}, + > {"id":4,"name":"Special Case: \"Quotes\""}] > (1 row) > ``` > > If this feature had already been released, I would not think it worth changing just for formatting. But since "FORMAT json" is a new PG19 feature and has not been released yet, I think it is better to make the output to follow the more common style. > > This patch changes the output to place the comma at the end of the previous line instead. The fix only adjusts how commas and newlines are emitted. It does not buffer the whole result, so it should not have any performance impact. > > See the attached patch for details. > > Best regards, > -- > Chao Li (Evan) > HighGo Software Co., Ltd. > https://www.highgo.com/ > > > Thanks for the patch, I like it as I feel better with placing commas at the end of lines. I have a small suggestion. The function name CopySendTextLikeEOL reads very similar to the existing CopySendTextLikeEndOfRow. Would it better to rename it to CopySendTextLikeLineTerminator? Other than that, the patch looks good to me. Regards, Alex Guo