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 1w3Fu5-0013IE-30 for pgsql-hackers@arkaria.postgresql.org; Thu, 19 Mar 2026 16:07:21 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w3Ft4-000w0B-0x for pgsql-hackers@arkaria.postgresql.org; Thu, 19 Mar 2026 16:06:18 +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 1w3Ft3-000w03-2R for pgsql-hackers@lists.postgresql.org; Thu, 19 Mar 2026 16:06:18 +0000 Received: from mail-yw1-x1131.google.com ([2607:f8b0:4864:20::1131]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1w3Ft2-000000001Yh-1MeT for pgsql-hackers@postgresql.org; Thu, 19 Mar 2026 16:06:17 +0000 Received: by mail-yw1-x1131.google.com with SMTP id 00721157ae682-798374d0f44so32494407b3.0 for ; Thu, 19 Mar 2026 09:06:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=joeconway.com; s=google; t=1773936376; x=1774541176; darn=postgresql.org; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=u8olYOcBT+0Id4vzTLweD0fzmhPYrB3PnkQO5x8ahTA=; b=YXD0ldlAjyGDW8zBrqIneMKNcIbXWMyNpbA1Oj8/W/7pQq/GMjyHW9apySynsq8eH8 uCB8CbpdjPU5HEse0tONXrff5WQ+7ZHm4PypXSjF5+BVS4oAtHRHgIKbBPUNPqD17PQ+ Q97/KiP5hoE/UYkKQ5hxzUdRez6EdApWnDe2ZY589rq4CSzkzGfD/F3mNT7hsDW/XIsK KNOJJMEUnNo/TzwOreVj8mjBFqMYsB/8R8X0wffOJeecKBP5IZnQhRnqtY9zRKnCctuW uMUpZYQ2FcNX+qIhASSbb+BWfF6SAB/uDT5koPH9lkl1PfNla0gaH1+Se6Z5I8NDWnGg 0iXA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773936376; x=1774541176; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc: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=u8olYOcBT+0Id4vzTLweD0fzmhPYrB3PnkQO5x8ahTA=; b=iD5EfLts6cixY7tNS8trrOID24bf8pYz8Kr5FaF0JBXtnCPuYftlfdKZFADUM+sp+F Cn9eWCjkivhN6C1X4iIuoE1uF6Vj8eCXAUPzyZ/zskhyiBgjunAh4rdgHzyuPmyXMe1Q +EU309I3Cp60wdp9iefyUJOUA3ApNV+wYOS859eypFv2BhGDWnTZ9vaWSOwKfdzhlKUJ AwsP7rtxLAwalKfY/ME0uD9lrkYZ2zzjSLlV13kiTzFSqXsVkzlXupDC+CHMj4X7F1as FURU0dn1eCmf2/BEiAp/UdkJPeCyYMKUN6BUWQs15YpsGcKi/1IGC5kXJ+UiBI0L5REK jDiw== X-Forwarded-Encrypted: i=1; AJvYcCV3VCuSnZyjZnMdaBvy3oDBOz3EDIuXQIXDsjcigT8GCvh9os0IGw+EEELbNWVTO7Iw+3v5LYkDKoMoe4cr@postgresql.org X-Gm-Message-State: AOJu0Yzi48BsTC+EOWDrhMI6CxlDW1OfgW5S6B6Y6oXYFgvtuFYz3WWt lPF8JkP+KCcVBRrWeMnK/WLxLAmtGM9yuUlwcLIFdzCQCcNgGkh8mB05R2bnoBzPJo8= X-Gm-Gg: ATEYQzzgiHdjtmZR1MwyQg9O4JhX/sYcyHv6g8zThrc1JAXT/a59HLb2McJwNsgkRRc ++Ih/40Tmw6CE8ei/Ra0ePx8g/B0banoZR9V5VCkIY2mi5x8WRWf2WIH4uWKPY/EWT2LPOTGUon gTRjlCRWmtTtnS/F1LnW32gs/Vyxm7anf5NOQ6kEaPnaZFCjhY1P1U5RdV50U8VLjcegjTjrgcD 1KuxzmsU1yy5YWad0RgkDXBeuCwcUqEbJP4ZeQXoj6A97fRyN4aa6Va9PgAlq83aBR9AjKetf+S qJmmzqh4fue90yGN4bDZYS/pKpfbYq+kd9OmmuuhTV52MkglfoudDMPkNMQVm8o2wvZ/G441BFA yEsuU3Mu2gIkJXFRo6F39vglwnP7J8agmUqPX6OCPgEuMTDHEgd8D5SclFU2x3bJY8Q85/O5mHc vSuvYBjO1l6rab4lpyYs2g0vlt X-Received: by 2002:a05:690c:60c2:b0:797:d46b:e86e with SMTP id 00721157ae682-79a81a90a25mr40452967b3.14.1773936375342; Thu, 19 Mar 2026 09:06:15 -0700 (PDT) Received: from [192.168.4.42] ([46.110.138.68]) by smtp.gmail.com with ESMTPSA id 00721157ae682-79a711657b8sm39421867b3.0.2026.03.19.09.06.14 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 19 Mar 2026 09:06:14 -0700 (PDT) Message-ID: <90984087-723c-48e6-88ca-661ed15b2dd6@joeconway.com> Date: Thu, 19 Mar 2026 12:06:13 -0400 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: Emitting JSON to file using COPY TO To: Andrew Dunstan , jian he , Daniel Verite Cc: Masahiko Sawada , Junwang Zhao , Florents Tselai , "Andrey M. Borodin" , Dean Rasheed , Davin Shearer , PostgreSQL development References: <964a3377-d957-4a06-ad02-8228aefa65fc@dunslane.net> <8428eb0f-f467-4cbd-a510-5be4f29b9ad7@dunslane.net> Content-Language: en-US From: Joe Conway In-Reply-To: <8428eb0f-f467-4cbd-a510-5be4f29b9ad7@dunslane.net> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 3/19/26 11:02, Andrew Dunstan wrote: > > On 2026-03-18 We 9:58 PM, jian he wrote: >> On Wed, Mar 18, 2026 at 10:37 PM Daniel Verite wrote: >>> Currently there's no difference in output between the null >>> json value and the SQL null. >>> >>> postgres=# create table tbl (j jsonb); >>> postgres=# insert into tbl values('null'); >>> postgres=# insert into tbl values(null); >>> postgres=# copy tbl to stdout with (format json); >>> {"j":null} >>> {"j":null} >>> >>> Does it have to be that way or are there valid distinct outputs >>> that we could use to avoid this ambiguity? >>> >> This is an existing (quite old) behavior of >> composite_to_json->datum_to_json_internal, IMHO. >> >> ``` >> if (is_null) >> { >> appendBinaryStringInfo(result, "null", strlen("null")); >> return; >> } >> ``` >> produce the same results as >> ``` >> case JSONTYPE_JSON: >> /* JSON and JSONB output will already be escaped */ >> outputstr = OidOutputFunctionCall(outfuncoid, val); >> appendStringInfoString(result, outputstr); >> pfree(outputstr); >> break; >> ``` >> >> Therefore I intended to document it as below: >> >> >> JSON Format >> >> When the json format is used, data is >> exported with one JSON object per line, >> where each line corresponds to a single record. >> The json format has no standard way to >> distinguish between an SQL NULL and a JSON >> null literal. >> In the examples that follow, the following table containing JSON >> data will be used: >> >> CREATE TABLE my_test (a jsonb, b int); >> INSERT INTO my_test VALUES ('null', 1), (NULL, 1); >> >> >> When exporting this table using the json format: >> >> COPY my_test TO STDOUT (FORMAT JSON); >> >> In the resulting output, both the SQL NULL and >> the JSON null are rendered identically: >> >> {"a":null,"b":1} >> {"a":null,"b":1} >> >> >> >> >> >> >> what do you think? >> >> >> > > I can live with that, if others can. +1 WFM -- Joe Conway PostgreSQL Contributors Team Amazon Web Services: https://aws.amazon.com