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.94.2) (envelope-from ) id 1rNOpt-00Bbcd-95 for pgsql-hackers@arkaria.postgresql.org; Wed, 10 Jan 2024 03:00:59 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1rNOpr-00H9gy-2F for pgsql-hackers@arkaria.postgresql.org; Wed, 10 Jan 2024 03:00:55 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rNOpp-00H9gq-Ry for pgsql-hackers@lists.postgresql.org; Wed, 10 Jan 2024 03:00:54 +0000 Received: from mail.clear-code.com ([153.126.206.245]) by magus.postgresql.org with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rNOpl-000l04-5n for pgsql-hackers@postgresql.org; Wed, 10 Jan 2024 03:00:52 +0000 Received: from localhost (unknown [IPv6:2404:7a80:89c1:1200:6af9:2266:1443:f149]) by mail.clear-code.com (Postfix) with ESMTPSA id 3BD0B5E7BA6; Wed, 10 Jan 2024 12:00:40 +0900 (JST) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.clear-code.com 3BD0B5E7BA6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=clear-code.com; s=default; t=1704855640; bh=gGNqOKUYgt5kQ4u0LySo69l9TKlbVSA2AJF1meKUiko=; h=Date:To:Cc:Subject:From:In-Reply-To:References:From; b=CgGdixAIFyNz6IPsq0ioa7ee0rGogGR4bsr7TM9YeCaOg5hvvLy7tH6pJfzM94v1J an/GM2q6TBM92IC9ISOyJ8pUyM8vl5+ai3+cbYa1U77wrdEOztm9cvMplFD0+3GS5W kdb3L80+9M9ReyyZdTj+wY8dRB6XLN74AC8z6lF8= Date: Wed, 10 Jan 2024 12:00:34 +0900 (JST) Message-Id: <20240110.120034.501385498034538233.kou@clear-code.com> To: michael@paquier.xyz Cc: sawada.mshk@gmail.com, zhjwpku@gmail.com, andrew@dunslane.net, nathandbossart@gmail.com, pgsql-hackers@postgresql.org Subject: Re: Make COPY format extendable: Extract COPY TO format implementations From: Sutou Kouhei In-Reply-To: References: <20231221.183504.1240642084042888377.kou@clear-code.com> X-Mailer: Mew version 6.8 on Emacs 29.1 Mime-Version: 1.0 Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Rspamd-Queue-Id: 3BD0B5E7BA6 X-Rspamd-Server: mail.clear-code.com X-Spamd-Result: default: False [2.90 / 999.00]; SUSPICIOUS_RECIPS(1.50)[]; MID_CONTAINS_FROM(1.00)[]; MV_CASE(0.50)[]; MIME_GOOD(-0.10)[text/plain]; ASN(0.00)[asn:2518, ipnet:2404:7a80::/29, country:JP]; MIME_TRACE(0.00)[0:+]; ARC_NA(0.00)[]; RCVD_COUNT_ZERO(0.00)[0]; TAGGED_RCPT(0.00)[]; FREEMAIL_ENVRCPT(0.00)[gmail.com]; URIBL_BLOCKED(0.00)[localhost:helo,paquier.xyz:email,postgresql.org:url]; TO_MATCH_ENVRCPT_ALL(0.00)[]; FREEMAIL_CC(0.00)[gmail.com,dunslane.net,postgresql.org]; RCPT_COUNT_FIVE(0.00)[6]; FROM_HAS_DN(0.00)[]; TO_DN_NONE(0.00)[]; FROM_EQ_ENVFROM(0.00)[]; SURBL_MULTI_FAIL(0.00)[paquier.xyz:server fail,postgresql.org:server fail,localhost:server fail] X-Rspamd-Action: no action List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi, In "Re: Make COPY format extendable: Extract COPY TO format implementations" on Fri, 22 Dec 2023 10:00:24 +0900, Michael Paquier wrote: >> 3. Export CopySend*() >> >> * If we like minimum API, we just need to export >> CopySendData() and CopySendEndOfRow(). But >> CopySend{String,Char,Int32,Int16}() will be convenient >> custom COPY TO handlers. (A custom COPY TO handler for >> Apache Arrow doesn't need them.) > > Hmm. Not sure on this one. This may come down to externalize the > manipulation of fe_msgbuf. Particularly, could it be possible that > some custom formats don't care at all about the network order? It means that all custom formats should control byte order by themselves instead of using CopySendInt*() that always use network byte order, right? It makes sense. Let's export only CopySendData() and CopySendEndOfRow(). >> 1. What value should be used for "format" in >> PgMsg_CopyOutResponse message? >> >> It's 1 for binary format and 0 for text/csv format. >> >> Should we make it customizable by custom COPY TO handler? >> If so, what value should be used for this? > > Interesting point. It looks very tempting to give more flexibility to > people who'd like to use their own code as we have one byte in the > protocol but just use 0/1. Hence it feels natural to have a callback > for that. OK. Let's add a callback something like: typedef int16 (*CopyToGetFormat_function) (CopyToState cstate); > It also means that we may want to think harder about copy_is_binary in > libpq in the future step. Now, having a backend implementation does > not need any libpq bits, either, because a client stack may just want > to speak the Postgres protocol directly. Perhaps a custom COPY > implementation would be OK with how things are in libpq, as well, > tweaking its way through with just text or binary. Can we defer this discussion after we commit a basic custom COPY format handler mechanism? >> 2. Do we need more tries for design discussion for the first >> implementation? If we need, what should we try? > > A makeNode() is used with an allocation in the current memory context > in the function returning the handler. I would have assume that this > stuff returns a handler as a const struct like table AMs. If we use this approach, we can't use the Sawada-san's idea[1] that provides a convenient API to hide CopyFormatRoutine internal. The idea provides MakeCopy{To,From}FormatRoutine(). They return a new CopyFormatRoutine* with suitable is_from member. They can't use static const CopyFormatRoutine because they may be called multiple times in the same process. We can use the satic const struct approach by choosing one of the followings: 1. Use separated function for COPY {TO,FROM} format handlers as I suggested. 2. Don't provide convenient API. Developers construct CopyFormatRoutine by themselves. But it may be a bit tricky. 3. Similar to 2. but don't use a bit tricky approach (don't embed Copy{To,From}FormatRoutine nodes into CopyFormatRoutine). Use unified function for COPY {TO,FROM} format handlers but CopyFormatRoutine always have both of COPY {TO,FROM} format routines and these routines aren't nodes: typedef struct CopyToFormatRoutine { CopyToStart_function start_fn; CopyToOneRow_function onerow_fn; CopyToEnd_function end_fn; } CopyToFormatRoutine; /* XXX: just copied from COPY TO routines */ typedef struct CopyFromFormatRoutine { CopyFromStart_function start_fn; CopyFromOneRow_function onerow_fn; CopyFromEnd_function end_fn; } CopyFromFormatRoutine; typedef struct CopyFormatRoutine { NodeTag type; CopyToFormatRoutine to_routine; CopyFromFormatRoutine from_routine; } CopyFormatRoutine; ---- static const CopyFormatRoutine testfmt_handler = { .type = T_CopyFormatRoutine, .to_routine = { .start_fn = testfmt_copyto_start, .onerow_fn = testfmt_copyto_onerow, .end_fn = testfmt_copyto_end, }, .from_routine = { .start_fn = testfmt_copyfrom_start, .onerow_fn = testfmt_copyfrom_onerow, .end_fn = testfmt_copyfrom_end, }, }; PG_FUNCTION_INFO_V1(copy_testfmt_handler); Datum copy_testfmt_handler(PG_FUNCTION_ARGS) { PG_RETURN_POINTER(&testfmt_handler); } 4. ... other idea? [1] https://www.postgresql.org/message-id/flat/CAD21AoDs9cOjuVbA_krGizAdc50KE%2BFjAuEXWF0NZwbMnc7F3Q%40mail.gmail.com#71bb03d9237252382b245dd33e705a3a Thanks, -- kou