Subject: Re: Make COPY format extendable: Extract COPY TO format implementations

From: Masahiko Sawada <[email-masked]>
Date: Mon, 17 Mar 2025 13:50:03 -0700

On Tue, Mar 4, 2025 at 4:06 PM Sutou Kouhei <[email-masked]> wrote:
>
> Hi,
>
> In <[email-masked]>
>   "Re: Make COPY format extendable: Extract COPY TO format implementations" on Mon, 3 Mar 2025 11:06:39 -0800,
>   Masahiko Sawada <[email-masked]> wrote:
>
> > I agree with the fix and the patch looks good to me. I've updated the
> > commit message and am going to push, barring any objections.
>
> Thanks!
>
> I've rebased the patch set. Here is a summary again:

Thank you for updating the patches. Here are some review comments on
the 0001 patch:

+   if (strcmp(format, "text") == 0)
+   {
+       /* "csv_mode == false && binary == false" means "text" */
+       return;
+   }
+   else if (strcmp(format, "csv") == 0)
+   {
+       opts_out->csv_mode = true;
+       return;
+   }
+   else if (strcmp(format, "binary") == 0)
+   {
+       opts_out->binary = true;
+       return;
+   }
+
+   /* custom format */
+   if (!is_from)
+   {
+       funcargtypes[0] = INTERNALOID;
+       handlerOid = LookupFuncName(list_make1(makeString(format)), 1,
+                                   funcargtypes, true);
+   }
+   if (!OidIsValid(handlerOid))
+       ereport(ERROR,
+               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                errmsg("COPY format \"%s\" not recognized", format),
+                parser_errposition(pstate, defel->location)));

I think that built-in formats also need to have their handler
functions. This seems to be a conventional way for customizable
features such as tablesample and access methods, and we can simplify
this function.

---
I think we need to update the documentation to describe how users can
define the handler functions and what each callback function is
responsible for.

Regards,

-- 
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com

---

From: Sutou Kouhei <[email-masked]>
Date: Wed, 19 Mar 2025 11:56:17 +0900 (JST)

Hi,

In <CAD21AoDU=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Mon, 17 Mar 2025 13:50:03 -0700,

> features such as tablesample and access methods, and we can simplify

OK. 0008 in the attached v37 patch set does it.

> define the handler functions and what each callback function is

I agree with it but we haven't finalized public APIs yet. Can
we defer it after we finalize public APIs? (Proposed public
APIs exist in 0003, 0006 and 0007.)

And could someone help (take over if possible) writing a
document for this feature? I'm not good at writing a
document in English... 0009 in the attached v37 patch set
has a draft of it. It's based on existing documents in
doc/src/sgml/ and *.h.

0001-0007 aren't changed from v36 patch set.

Thanks,
-- 
kou

---

From: "David G. Johnston" <[email-masked]>
Date: Wed, 19 Mar 2025 17:49:49 -0700

> has a draft of it. It's based on existing documents in
I haven't touched the innards of the structs aside from changing
programlisting to synopsis.  And redoing the two section opening paragraphs
to better integrate with the content in the chapter opening.

The rest I kinda went to town on...

David J.

diff --git a/doc/src/sgml/copy-handler.sgml b/doc/src/sgml/copy-handler.sgml
index f602debae6..9d2897a104 100644
--- a/doc/src/sgml/copy-handler.sgml
+++ b/doc/src/sgml/copy-handler.sgml
@@ -10,56 +10,72 @@
  <para>
   <productname>PostgreSQL</productname> supports
   custom <link linkend="sql-copy"><literal>COPY</literal></link>
-  handlers. The <literal>COPY</literal> handlers can use different copy
format
-  instead of built-in <literal>text</literal>, <literal>csv</literal>
-  and <literal>binary</literal>.
+  handlers; adding additional <replaceable>format_name</replaceable>
options
+  to the <literal>FORMAT</literal> clause.
  </para>

  <para>
-  At the SQL level, a table sampling method is represented by a single SQL
-  function, typically implemented in C, having the signature
-<programlisting>
-format_name(internal) RETURNS copy_handler
-</programlisting>
-  The name of the function is the same name appearing in
-  the <literal>FORMAT</literal> option. The <type>internal</type> argument
is
-  a dummy that simply serves to prevent this function from being called
-  directly from an SQL command. The real argument is <literal>bool
-  is_from</literal>. If the handler is used by <literal>COPY
FROM</literal>,
-  it's <literal>true</literal>. If the handler is used by <literal>COPY
-  FROM</literal>, it's <literal>false</literal>.
+  At the SQL level, a copy handler method is represented by a single SQL
+  function (see <xref linkend="sql-createfunction"/>), typically
implemented in
+  C, having the signature
+<synopsis>
+<replaceable>format_name</replaceable>(internal) RETURNS
<literal>copy_handler</literal>
+</synopsis>
+  The function's name is then accepted as a valid
<replaceable>format_name</replaceable>.
+  The return pseudo-type <literal>copy_handler</literal> informs the
system that
+  this function needs to be registered as a copy handler.
+  The <type>internal</type> argument is a dummy that prevents
+  this function from being called directly from an SQL command.  As the
+  handler implementation must be server-lifetime immutable; this SQL
function's
+  volatility should be marked immutable.  The
<literal>link_symbol</literal>
+  for this function is the name of the implementation function, described
next.
  </para>

  <para>
-  The function must return <type>CopyFromRoutine *</type> when
-  the <literal>is_from</literal> argument is <literal>true</literal>.
-  The function must return <type>CopyToRoutine *</type> when
-  the <literal>is_from</literal> argument is <literal>false</literal>.
+  The implementation function signature expected for the function named
+  in the <literal>link_symbol</literal> is:
+<synopsis>
+Datum
+<replaceable>copy_format_handler</replaceable>(PG_FUNCTION_ARGS)
+</synopsis>
+  The convention for the name is to replace the word
+  <replaceable>format</replaceable> in the placeholder above with the
value given
+  to <replaceable>format_name</replaceable> in the SQL function.
+  The first argument is a <type>boolean</type> that indicates whether the
handler
+  must provide a pointer to its implementation for <literal>COPY
FROM</literal>
+  (a <type>CopyFromRoutine *</type>). If <literal>false</literal>, the
handler
+  must provide a pointer to its implementation of <literal>COPY
TO</literal>
+  (a <type>CopyToRoutine *</type>).  These structs are declared in
+  <filename>src/include/commands/copyapi.h</filename>.
  </para>

  <para>
-  The <type>CopyFromRoutine</type> and <type>CopyToRoutine</type> struct
types
-  are declared in <filename>src/include/commands/copyapi.h</filename>,
-  which see for additional details.
+  The structs hold pointers to implementation functions for
+  initializing, starting, processing rows, and ending a copy operation.
+  The specific structures vary a bit between <literal>COPY FROM</literal>
and
+  <literal>COPY TO</literal> so the next two sections describes each
+  in detail.
  </para>

  <sect1 id="copy-handler-from">
   <title>Copy From Handler</title>

   <para>
-   The <literal>COPY</literal> handler function for <literal>COPY
-   FROM</literal> returns a <type>CopyFromRoutine</type> struct containing
-   pointers to the functions described below. All functions are required.
+   The opening to this chapter describes how the executor will call the
+   main handler function with, in this case,
+   a <type>boolean</type> <literal>true</literal>, and expect to receive a
+   <type>CopyFromRoutine *</type> <type>Datum</type>.  This section
describes
+   the components of the <type>CopyFromRoutine</type> struct.
   </para>

   <para>
-<programlisting>
+<synopsis>
 void
 CopyFromInFunc(CopyFromState cstate,
                Oid atttypid,
                FmgrInfo *finfo,
                Oid *typioparam);
-</programlisting>
+</synopsis>

    This sets input function information for the
    given <literal>atttypid</literal> attribute. This function is called
once
@@ -110,11 +126,11 @@ CopyFromInFunc(CopyFromState cstate,
   </para>

   <para>
-<programlisting>
+<synopsis>
 void
 CopyFromStart(CopyFromState cstate,
               TupleDesc tupDesc);
-</programlisting>
+</synopsis>

    This starts a <literal>COPY FROM</literal>. This function is called
once at
    the beginning of <literal>COPY FROM</literal>.
@@ -144,13 +160,13 @@ CopyFromStart(CopyFromState cstate,
   </para>

   <para>
-<programlisting>
+<synopsis>
 bool
 CopyFromOneRow(CopyFromState cstate,
                ExprContext *econtext,
                Datum *values,
                bool *nulls);
-</programlisting>
+</synopsis>

    This reads one row from the source and fill <literal>values</literal>
    and <literal>nulls</literal>. If there is one or more tuples to be read,
@@ -202,10 +218,10 @@ CopyFromOneRow(CopyFromState cstate,
   </para>

   <para>
-<programlisting>
+<synopsis>
 void
 CopyFromEnd(CopyFromState cstate);
-</programlisting>
+</synopsis>

    This ends a <literal>COPY FROM</literal>. This function is called once
at
    the end of <literal>COPY FROM</literal>.
@@ -232,18 +248,20 @@ CopyFromEnd(CopyFromState cstate);
   <title>Copy To Handler</title>

   <para>
-   The <literal>COPY</literal> handler function for <literal>COPY
-   TO</literal> returns a <type>CopyToRoutine</type> struct containing
-   pointers to the functions described below. All functions are required.
+   The opening to this chapter describes how the executor will call the
+   main handler function with, in this case,
+   a <type>boolean</type> <literal>false</literal>, and expect to receive a
+   <type>CopyInRoutine *</type> <type>Datum</type>.  This section describes
+   the components of the <type>CopyInRoutine</type> struct.
   </para>

   <para>
-<programlisting>
+<synopsis>
 void
 CopyToOutFunc(CopyToState cstate,
               Oid atttypid,
               FmgrInfo *finfo);
-</programlisting>
+</synopsis>

    This sets output function information for the
    given <literal>atttypid</literal> attribute. This function is called
once
@@ -284,11 +302,11 @@ CopyToOutFunc(CopyToState cstate,
   </para>

   <para>
-<programlisting>
+<synopsis>
 void
 CopyToStart(CopyToState cstate,
             TupleDesc tupDesc);
-</programlisting>
+</synopsis>

    This starts a <literal>COPY TO</literal>. This function is called once
at
    the beginning of <literal>COPY TO</literal>.
@@ -316,11 +334,11 @@ CopyToStart(CopyToState cstate,
   </para>

   <para>
-<programlisting>
+<synopsis>
 bool
 CopyToOneRow(CopyToState cstate,
              TupleTableSlot *slot);
-</programlisting>
+</synopsis>

    This writes one row stored in <literal>slot</literal> to the
destination.

@@ -347,10 +365,10 @@ CopyToOneRow(CopyToState cstate,
   </para>

   <para>
-<programlisting>
+<synopsis>
 void
 CopyToEnd(CopyToState cstate);
-</programlisting>
+</synopsis>

    This ends a <literal>COPY TO</literal>. This function is called once at
    the end of <literal>COPY TO</literal>.

---

From: Sutou Kouhei <[email-masked]>
Date: Thu, 20 Mar 2025 10:24:55 +0900 (JST)

Hi,

In <CAKFQuwaMAFMHqxDXR=SxA0mDjdmntrwxZd2w=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Wed, 19 Mar 2025 17:49:49 -0700,

> The rest I kinda went to town on...

Thanks!!! It's very helpful!!!

I've applied your patch. 0009 is only changed.

Thanks,
-- 
kou

---

From: "David G. Johnston" <[email-masked]>
Date: Fri, 21 Mar 2025 17:31:54 -0700

On Tue, Mar 18, 2025 at 7:56 PM Sutou Kouhei <[email-masked]> wrote:

>   "Re: Make COPY format extendable: Extract COPY TO format
> implementations" on Mon, 17 Mar 2025 13:50:03 -0700,
tl/dr;

We need to exclude from our SQL function search any function that doesn't
declare copy_handler as its return type.
("function text must return type copy_handler" is not an acceptable error
message)

We need to accept identifiers in FORMAT and parse the optional catalog,
schema, and object name portions.
(Restrict our function search to the named schema if provided.)

Detail:

Fun thing...(not sure how much of this is covered above: I do see, but
didn't scour, the security discussion):

-- create some poison
create function public.text(internal) returns boolean language c as
'/home/davidj/gotya/gotya', 'gotit';
CREATE FUNCTION

-- inject it
postgres=# set search_path to public,pg_catalog;
SET

-- watch it die
postgres=# copy (select 1) to stdout (format text);
ERROR:  function text must return type copy_handler
LINE 1: copy (select 1) to stdout (format text);

I'm especially concerned about extensions here.

We shouldn't be locating any SQL function that doesn't have a copy_handler
return type.  Unfortunately, LookupFuncName seems incapable of doing what
we want here.  I suggest we create a new lookup routine where we can
specify the return argument type as a required element.  That would cleanly
mitigate the denial-of-service attack/accident vector demonstrated above
(the text returning function should have zero impact on how this feature
behaves).  If someone does create a handler SQL function without using
copy_handler return type we'd end up showing "COPY format 'david' not
recognized" - a developer should be able to figure out they didn't put a
correct return type on their handler function and that is why the system
did not register it.

A second concern is simply people wanting to name things the same; or, why
namespaces were invented.

Can we just accept a proper identifier after FORMAT so we can use
schema-qualified names?

(FORMAT "davescopyformat"."david")

We can special case the internal schema-less names and internally force
pg_catalog to avoid them being shadowed.

David J.

---

From: Masahiko Sawada <[email-masked]>
Date: Fri, 21 Mar 2025 22:07:50 -0700

On Fri, Mar 21, 2025 at 5:32 PM David G. Johnston
<[email-masked]> wrote:
> We need to exclude from our SQL function search any function that doesn't declare copy_handler as its return type.
> ("function text must return type copy_handler" is not an acceptable error message)
>
> We need to accept identifiers in FORMAT and parse the optional catalog, schema, and object name portions.
> Fun thing...(not sure how much of this is covered above: I do see, but didn't scour, the security discussion):
>
> -- create some poison
> create function public.text(internal) returns boolean language c as '/home/davidj/gotya/gotya', 'gotit';
> CREATE FUNCTION
>
> -- inject it
> We shouldn't be locating any SQL function that doesn't have a copy_handler return type.  Unfortunately, LookupFuncName seems incapable of doing what we want here.  I suggest we create a new lookup routine where we can specify the return argument type as a required element.  That would cleanly mitigate the denial-of-service attack/accident vector demonstrated above (the text returning function should have zero impact on how this feature behaves).  If someone does create a handler SQL function without using copy_handler return type we'd end up showing "COPY format 'david' not recognized" - a developer should be able to figure out they didn't put a correct return type on their handler function and that is why the system did not register it.

Just to be clear, the patch checks the function's return type before calling it:

       funcargtypes[0] = INTERNALOID;
       handlerOid = LookupFuncName(list_make1(makeString(format)), 1,

funcargtypes, true);
       if (!OidIsValid(handlerOid))
               ereport(ERROR,
                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                errmsg("COPY format \"%s\" not
recognized", format),
                                parser_errposition(pstate, defel->location)));

       /* check that handler has correct return type */
       if (get_func_rettype(handlerOid) != COPY_HANDLEROID)
               ereport(ERROR,
                               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                errmsg("function %s must return type %s",
                                               format, "copy_handler"),
                                parser_errposition(pstate, defel->location)));

So would changing the error message to like "COPY format 'text' not
recognized" untangle your concern?

FYI the same is true for TABLESAMPLE; it invokes a function with the
specified method name and checks the returned Node type:

=# select * from pg_class tablesample text (0);
ERROR:  function text must return type tsm_handler

A difference between TABLESAMPLE and COPY format is that the former
accepts a qualified name but the latter doesn't:

=# create extension tsm_system_rows ;
=# create schema s1;
=# create function s1.system_rows(internal) returns void language c as
'tsm_system_rows.so', 'tsm_system_rows_handler';
=# \df *.system_rows
                          List of functions
 Schema |    Name     | Result data type | Argument data types | Type
--------+-------------+------------------+---------------------+------
 public | system_rows | tsm_handler      | internal            | func
 s1     | system_rows | void             | internal            | func
(2 rows)
postgres(1:1194923)=# select count(*) from pg_class tablesample system_rows(0);
 count
-------
     0
(1 row)

postgres(1:1194923)=# select count(*) from pg_class tablesample
s1.system_rows(0);
ERROR:  function s1.system_rows must return type tsm_handler

> A second concern is simply people wanting to name things the same; or, why namespaces were invented.

Yeah, I think that the custom COPY format should support qualified
names at least.

Regards,

---

From: "David G. Johnston" <[email-masked]>
Date: Fri, 21 Mar 2025 22:23:56 -0700

On Friday, March 21, 2025, Masahiko Sawada <[email-masked]> wrote:

> > We need to exclude from our SQL function search any function that
> doesn't declare copy_handler as its return type.
> > We shouldn't be locating any SQL function that doesn't have a
> copy_handler return type.  Unfortunately, LookupFuncName seems incapable of
> doing what we want here.  I suggest we create a new lookup routine where we
> can specify the return argument type as a required element.  That would
> cleanly mitigate the denial-of-service attack/accident vector demonstrated
> above (the text returning function should have zero impact on how this
> feature behaves).  If someone does create a handler SQL function without
> using copy_handler return type we'd end up showing "COPY format 'david' not

In my example above copy should not fail at all.  The text function created
in public that returns Boolean would never be seen and the real one in
pg_catalog would then be found and behave as expected.

> ERROR:  function text must return type tsm_handler

Then this would benefit from the new function I suggest creating since it
apparently has the same, IMO, bug.

David J.

---

From: "David G. Johnston" <[email-masked]>
Date: Sat, 22 Mar 2025 10:11:10 -0700

> apparently has the same, IMO, bug.
Concretely like I posted here:
https://www.postgresql.org/message-id/[email-masked]

David J.

---

From: Masahiko Sawada <[email-masked]>
Date: Sun, 23 Mar 2025 02:01:59 -0700

> I've applied your patch. 0009 is only changed.

Thank you for updating the patches. I've reviewed the main part of
supporting the custom COPY format. Here are some random comments:

---
+/*
+ * Process the "format" option.
+ *
+ * This function checks whether the option value is a built-in format such as
+ * "text" and "csv" or not. If the option value isn't a built-in format, this
+ * function finds a COPY format handler that returns a CopyToRoutine (for
+ * is_from == false) or CopyFromRountine (for is_from == true). If no COPY
+ * format handler is found, this function reports an error.
+ */

I think this comment needs to be updated as the part "If the option
value isn't ..." is no longer true.

I think we don't necessarily need to create a separate function
ProcessCopyOptionFormat for processing the format option.

We need more regression tests for handling the given format name. For example,

- more various input patterns.
- a function with the specified format name exists but it returns an
unexpected Node.
- looking for a handler function in a different namespace.
etc.

---
I think that we should accept qualified names too as the format name
like tablesample does. That way, different extensions implementing the
same format can be used.

---
+        if (routine == NULL || !IsA(routine, CopyFromRoutine))
+                ereport(
+                                ERROR,
+                                (errcode(
+
ERRCODE_INVALID_PARAMETER_VALUE),
+                                 errmsg("COPY handler function "
+                                                "%u did not return "
+                                                "CopyFromRoutine struct",
+                                                opts->handler)));

It's not conventional to put a new line between 'ereport(' and 'ERROR'
(similarly between 'errcode(' and 'ERRCODE_...'. Also, we don't need
to split the error message into multiple lines as it's not long.

---
+        if (routine == NULL || !IsA(routine, CopyToRoutine))
+                ereport(
+                                ERROR,
+                                (errcode(
+
ERRCODE_INVALID_PARAMETER_VALUE),
+                                 errmsg("COPY handler function "
+                                                "%u did not return "
+                                                "CopyToRoutine struct",
+                                                opts->handler)));

Same as the above comment.

---
+  descr => 'pseudo-type for the result of a copy to/from method function',

s/method function/format function/

---
+        Oid                    handler;                /* handler
function for custom format routine */

'handler' is used also for built-in formats.

---
+static void
+CopyFromInFunc(CopyFromState cstate, Oid atttypid,
+                           FmgrInfo *finfo, Oid *typioparam)
+{
+        ereport(NOTICE, (errmsg("CopyFromInFunc: atttypid=%d", atttypid)));
+}

OIDs could be changed across major versions even for built-in types. I
think it's better to avoid using it for tests.

---
+static void
+CopyToOneRow(CopyToState cstate, TupleTableSlot *slot)
+{
+        ereport(NOTICE, (errmsg("CopyToOneRow: tts_nvalid=%u",
slot->tts_nvalid)));
+}

Similar to the above comment, the field name 'tts_nvalid' might also
be changed in the future, let's use another name.

---
+static const CopyFromRoutine CopyFromRoutineTestCopyFormat = {
+        .type = T_CopyFromRoutine,
+        .CopyFromInFunc = CopyFromInFunc,
+        .CopyFromStart = CopyFromStart,
+        .CopyFromOneRow = CopyFromOneRow,
+        .CopyFromEnd = CopyFromEnd,
+};

I'd suggest not using the same function names as the fields.

---
+/*
+ * Export CopySendEndOfRow() for extensions. We want to keep
+ * CopySendEndOfRow() as a static function for
+ * optimization. CopySendEndOfRow() calls in this file may be optimized by a
+ * compiler.
+ */
+void
+CopyToStateFlush(CopyToState cstate)
+{
+        CopySendEndOfRow(cstate);
+}

Is there any reason to use a different name for public functions?

---
+/*
+ * Export CopyGetData() for extensions. We want to keep CopyGetData() as a
+ * static function for optimization. CopyGetData() calls in this file may be
+ * optimized by a compiler.
+ */
+int
+CopyFromStateGetData(CopyFromState cstate, void *dest, int minread,
int maxread)
+{
+        return CopyGetData(cstate, dest, minread, maxread);
+}
+

The same as the above comment.

---
+        /* For custom format implementation */
+        void      *opaque;                     /* private space */

How about renaming 'private'?

---
I've not reviewed the documentation patch yet but I think the patch
seems to miss the updates to the description of the FORMAT option in
the COPY command section.

---
I think we can reorganize the patch set as follows:

1. Create copyto_internal.h and change COPY_XXX to COPY_SOURCE_XXX and
COPY_DEST_XXX accordingly.
2. Support custom format for both COPY TO and COPY FROM.
3. Expose necessary helper functions such as CopySendEndOfRow().
4. Add CopyFromSkipErrorRow().
5. Documentation.

Regards,

---

From: Masahiko Sawada <[email-masked]>
Date: Mon, 24 Mar 2025 17:45:10 -0700

> I've applied your patch. 0009 is only changed.

FYI I've implemented an extension to add JSON Lines format as a custom
COPY format[1] to check the usability of the COPY format APIs. I think
that the exposed APIs are fairly simple and minimum. I didn't find the
deficiency and excess of exposed APIs for helping extensions but I
find that it would be better to describe what the one-row callback
should do to utilize the abstracted destination. For example, in order
to use CopyToStateFlush() to write out to the destination, extensions
should write the data to cstate->fe_msgbuf. We expose
CopyToStateFlush() but not for any functions to write data there such
as CopySendString(). It was a bit inconvenient to me but I managed to
write the data directly there by #include'ing copyto_internal.h.

Regards,

[1] https://github.com/MasahikoSawada/pg_copy_jsonlines

---

From: Sutou Kouhei <[email-masked]>
Date: Thu, 27 Mar 2025 12:28:40 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Sun, 23 Mar 2025 02:01:59 -0700,

> ProcessCopyOptionFormat for processing the format option.

Hmm. I think that this separated function will increase
readability by reducing indentation. But I've removed the
separation as you suggested. So the comment is also removed
entirely.

0002 includes this.

> - looking for a handler function in a different namespace.

I've added the following tests:

* Wrong input type handler without namespace
* Wrong input type handler with namespace
* Wrong return type handler without namespace
* Wrong return type handler with namespace
* Wrong return value (Copy*Routine isn't returned) handler without namespace
* Wrong return value (Copy*Routine isn't returned) handler with namespace
* Nonexistent handler
* Invalid qualified name
* Valid handler without namespace and without search_path
* Valid handler without namespace and with search_path
* Valid handler with namespace

0002 also includes this.

> like tablesample does. That way, different extensions implementing the

Implemented. It's implemented after parsing SQL. Is it OK?
(It seems that tablesample does it in parsing SQL.)

Because "WITH (FORMAT XXX)" is processed as a generic option
in gram.y. All generic options are processed as strings. So
I keep this.

Syntax is "COPY ... WITH (FORMAT 'NAMESPACE.HANDLER_NAME')"
not "COPY ... WITH (FORMAT 'NAMESPACE'.'HANDLER_NAME')"
because of this choice.

0002 also includes this.

> to split the error message into multiple lines as it's not long.

Oh, sorry. I can't remember why I used this... I think I
trusted pgindent...

> s/method function/format function/

Good catch. I used "handler function" not "format function"
because we use "handler" in other places.

> 'handler' is used also for built-in formats.

Updated in 0004.

> think it's better to avoid using it for tests.

Oh, I didn't know it. I've changed to use type name instead
of OID. It'll be more stable than OID.

> be changed in the future, let's use another name.

Hmm. If the field name is changed, we need to change this
code. So changing tests too isn't strange. Anyway, I used
more generic text.

> I'd suggest not using the same function names as the fields.

OK. I've added "Test" prefix.

> Is there any reason to use a different name for public functions?

In this patch set, I use "CopyFrom"/"CopyTo" prefixes for
public APIs for custom COPY FORMAT handler extensions. It
will help understanding related APIs. Is it strange in
PostgreSQL?

> How about renaming 'private'?

We should not use "private" because it's a keyword in
C++. If we use "private" here, we can't include this file
from C++ code.

> the COPY command section.

I defer this for now. We can revisit the last documentation
patch after we finalize our API. (Or could someone help us?)

> 4. Add CopyFromSkipErrorRow().

The attached v39 patch set uses the followings:

0001: Create copyto_internal.h and change COPY_XXX to
      COPY_SOURCE_XXX and COPY_DEST_XXX accordingly.
      (Same as 1. in your suggestion)
0002: Support custom format for both COPY TO and COPY FROM.
      (Same as 2. in your suggestion)
0003: Expose necessary helper functions such as CopySendEndOfRow()
      and add CopyFromSkipErrorRow().
      (3. + 4. in your suggestion)
0004: Define handler functions for built-in formats.
      (Not included in your suggestion)
0005: Documentation. (WIP)
      (Same as 5. in your suggestion)

We can merge 0001 quickly, right?

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Fri, 28 Mar 2025 22:37:03 -0700

> * Valid handler with namespace

Probably we can merge these newly added four files into one .sql file?

Also we need to add some comments to describe what these queries test.
For example, it's not clear to me at a glance what queries in
no-schema.sql are going to test as there is no comment there.

> (It seems that tablesample does it in parsing SQL.)

I think it's okay.

One problem in the following chunk I can see is:

+           qualified_format = stringToQualifiedNameList(format, NULL);
+           DeconstructQualifiedName(qualified_format, &schema, &fmt);
+           if (!schema || strcmp(schema, "pg_catalog") == 0)
+           {
+               if (strcmp(fmt, "csv") == 0)
+                   opts_out->csv_mode = true;
+               else if (strcmp(fmt, "binary") == 0)
+                   opts_out->binary = true;
+           }

Non-qualified names depend on the search_path value so it's not
necessarily a built-in format. If the user specifies 'csv' with
seach_patch = 'myschema, pg_catalog', the COPY command unnecessarily
sets csv_mode true. I think we can instead check if the retrieved
handler function's OID matches the built-in formats' ones. Also, it's
weired to me that cstate has csv_mode and binary fields even though
the format should have already been known by the callback functions.

Regarding the documentation for the existing options, it says "...
only when not using XXX format." some places, where XXX can be
replaced with binary or CSV. Once we support custom formats, 'non-CSV
mode' would actually include custom formats as well, so we need to
update the description too.

> code.

Yes, but if we use independe name in the NOTICE message we would not
need to update the expected files.

> will help understanding related APIs. Is it strange in

I see your point. Probably we need to find a better name as the name
CopyToStateFlush doesn't sound well like this API should be called
only once at the end of a row (IOW user might try to call it multiple
times to 'flush' the state while processing a row). How about
CopyToEndOfRow()?

> C++. If we use "private" here, we can't include this file

Understood.

>       (Same as 5. in your suggestion)

Can we merge 0002 and 0004?

> We can merge 0001 quickly, right?

I don't think it makes sense to push only 0001 as it's a completely
preliminary patch for subsequent patches. It would be prudent to push
it once other patches are ready too.

Regards,

---

From: "David G. Johnston" <[email-masked]>
Date: Fri, 28 Mar 2025 22:57:56 -0700

> the format should have already been known by the callback functions.

I considered it a feature that a schema-less reference to text, csv, or
binary always resolves to the core built-in handlers.  As does an
unspecified format default of text.

To use an extension that chooses to override that format name would require
schema qualification.

David J.

---

From: Sutou Kouhei <[email-masked]>
Date: Sat, 29 Mar 2025 17:57:53 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Fri, 28 Mar 2025 22:37:03 -0700,

> Probably we can merge these newly added four files into one .sql file?

I know that src/test/regress/sql/ uses this style (one .sql
file includes many test patterns in one large category). I
understand that the style is preferable in
src/test/regress/sql/ because src/test/regress/sql/ has
tests for many categories.

But do we need to follow the style in
src/test/modules/*/sql/ too? If we use the style in
src/test/modules/*/sql/, we need to have only one .sql in
src/test/modules/*/sql/ because src/test/modules/*/ are for
each category.

And the current .sql per sub-category style is easy to debug
(at least for me). For example, if we try qualified name
cases on debugger, we can use "\i sql/schema.sql" instead of
extracting target statements from .sql that includes many
unrelated statements. (Or we can use "\i sql/all.sql" and
many GDB "continue"s.)

BTW, it seems that src/test/modules/test_ddl_deparse/sql/
uses .sql per sub-category style. Should we use one .sql
file for sql/test/modules/test_copy_format/sql/? If it's
required for merging this patch set, I'll do it.

> no-schema.sql are going to test as there is no comment there.

Hmm. You refer no_schema.sql in 0002, right?

----
CREATE EXTENSION test_copy_format;
CREATE TABLE public.test (a smallint, b integer, c bigint);
INSERT INTO public.test VALUES (1, 2, 3), (12, 34, 56), (123, 456, 789);
COPY public.test FROM stdin WITH (FORMAT 'test_copy_format');
\.
COPY public.test TO stdout WITH (FORMAT 'test_copy_format');
DROP TABLE public.test;
DROP EXTENSION test_copy_format;
----

In general, COPY FORMAT tests focus on "COPY FROM WITH
(FORMAT ...)" and "COPY TO WITH (FORMAT ...)". And the file
name "no_schema" shows that it doesn't use qualified
name. Based on this, I feel that the above content is very
straightforward without any comment.

What should we add as comments? For example, do we need the
following comments?

----
-- This extension includes custom COPY handler: test_copy_format
CREATE EXTENSION test_copy_format;
-- Test data
CREATE TABLE public.test (a smallint, b integer, c bigint);
INSERT INTO public.test VALUES (1, 2, 3), (12, 34, 56), (123, 456, 789);
-- Use custom COPY handler, test_copy_format, without
-- schema for FROM.
COPY public.test FROM stdin WITH (FORMAT 'test_copy_format');
\.
-- Use custom COPY handler, test_copy_format, without
-- schema for TO.
COPY public.test TO stdout WITH (FORMAT 'test_copy_format');
-- Cleanup
DROP TABLE public.test;
DROP EXTENSION test_copy_format;
----

> sets csv_mode true.

I think that we should always use built-in COPY handlers for
(not-qualified) "text", "csv" and "binary" for
compatibility. If we allow custom COPY handlers for
(not-qualified) "text", "csv" and "binary", pg_dump or
existing dump may be broken. Because we must use the same
COPY handler when we dump (COPY TO) and we restore (COPY
FROM).

BTW, the current implementation always uses
pg_catalog.{text,csv,binary} for (not-qualified) "text",
"csv" and "binary" even when there are
myschema.{text,csv,binary}. See
src/test/modules/test_copy_format/sql/builtin.sql. But I
haven't looked into it why...

>                     I think we can instead check if the retrieved
> handler function's OID matches the built-in formats' ones.

I agree that the approach is clear than the current
implementation. I'll use it when I create the next patch
set.

>                                                            Also, it's

You refer CopyFomratOptions::{csv_mode,binary} not
Copy{To,From}StateData, right? And you suggest that we
should replace all opts.csv_mode and opts.binary with
opts.handler == F_CSV and opts.handler == F_BINARY, right?

We can do it but I suggest that we do it as a refactoring
(or cleanup) in a separated patch for easy to review.

> update the description too.

I agree with you.

> times to 'flush' the state while processing a row). How about

CopyToStateFlush() can be called multiple times in a row. It
can also be called only once with multiple rows. Because it
just flushes the current buffer.

Existing CopySendEndOfRow() is called at the end of a
row. (Buffer is flushed at the end of row.) So I think that
the "EndOfRow" was chosen.

Some custom COPY handlers may not be row based. For example,
Apache Arrow COPY handler doesn't flush buffer for each row.
So, we should provide "flush" API not "end of row" API for
extensibility.

> Can we merge 0002 and 0004?

Can we do it when we merge this patch set if it's still
desirable at the time? Because:

* I think that separated 0002 and 0004 patches are easier to
  review than squashed 0002 and 0004 patch.
* I still think that someone may don't like defining COPY
  handlers for built-in formats. If we don't define COPY
  handlers for built-in formats finally, we can just drop
  0004.

> it once other patches are ready too.

Hmm. I feel that 0001 is a refactoring category patch like
merged patches. In general, distinct enum value names are
easier to understand.

BTW, does the "other patches" include the documentation
patch...?

Thanks,
-- 
kou

---

From: "David G. Johnston" <[email-masked]>
Date: Sat, 29 Mar 2025 09:12:00 -0700

>   handlers for built-in formats finally, we can just drop

We should (and usually do) dog-food APIs when reasonable and this situation
seems quite reasonable.  I'd push back quite a bit about publishing this
without any internal code leveraging it.

> merged patches. In general, distinct enum value names are
I'm for pushing 0001.  We've had copyfrom_internal.h for a while now and
this seems like a simple refactor to make that area of the code cleaner via
symmetry.

David J.

---

From: "David G. Johnston" <[email-masked]>
Date: Sat, 29 Mar 2025 09:48:22 -0700

>       (Same as 5. in your suggestion)
I don't think this module should be responsible for testing the validity of
"qualified names in a string literal" behavior.  Having some of the tests
use a schema qualification, and I'd suggest explicit
double-quoting/case-folding, wouldn't hurt just to demonstrate it's
possible, and how extensions should be referenced, but definitely don't
need tests to prove the broken cases are indeed broken.  This relies on an
existing API that has its own tests.  It is definitely pointlessly
redundant to have 6 tests that only differ from 6 other tests in their use
of a schema qualification.

I prefer keeping 0002 and 0004 separate.  In particular, keeping the design
choice of "unqualified internal format names ignore search_path" should
stand out as its own commit.

David J.

---

From: Sutou Kouhei <[email-masked]>
Date: Sun, 30 Mar 2025 11:31:26 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Sat, 29 Mar 2025 09:48:22 -0700,

> of a schema qualification.

You suggest the followings, right?

1. Add tests for "Schema.Name" with mixed cases
2. Remove the following 6 tests in
   src/test/modules/test_copy_format/sql/invalid.sql

   ----
   COPY public.test FROM stdin WITH (FORMAT 'test_schema.test_copy_format_wrong_input_type');
   COPY public.test TO stdout WITH (FORMAT 'test_schema.test_copy_format_wrong_input_type');
   COPY public.test FROM stdin WITH (FORMAT 'test_schema.test_copy_format_wrong_return_type');
   COPY public.test TO stdout WITH (FORMAT 'test_schema.test_copy_format_wrong_return_type');
   COPY public.test FROM stdin WITH (FORMAT 'test_schema.test_copy_format_wrong_return_value');
   COPY public.test TO stdout WITH (FORMAT 'test_schema.test_copy_format_wrong_return_value');
   ----

   because we have the following 6 tests:

   ----
   SET search_path = public,test_schema;
   COPY public.test FROM stdin WITH (FORMAT 'test_copy_format_wrong_input_type');
   COPY public.test TO stdout WITH (FORMAT 'test_copy_format_wrong_input_type');
   COPY public.test FROM stdin WITH (FORMAT 'test_copy_format_wrong_return_type');
   COPY public.test TO stdout WITH (FORMAT 'test_copy_format_wrong_return_type');
   COPY public.test FROM stdin WITH (FORMAT 'test_copy_format_wrong_return_value');
   COPY public.test TO stdout WITH (FORMAT 'test_copy_format_wrong_return_value');
   RESET search_path;
   ----
3. Remove the following tests because the behavior must be
   tested in other places:

   ----
   COPY public.test FROM stdin WITH (FORMAT 'nonexistent');
   COPY public.test TO stdout WITH (FORMAT 'nonexistent');
   COPY public.test FROM stdin WITH (FORMAT 'invalid.qualified.name');
   COPY public.test TO stdout WITH (FORMAT 'invalid.qualified.name');
   ----

Does it miss something?

1.: There is no difference between single-quoting and
    double-quoting here. Because the information what quote
    was used for the given FORMAT value isn't remained
    here. Should we update gram.y?

2.: I don't have a strong opinion for it. If nobody objects
    it, I'll remove them.

3.: I don't have a strong opinion for it. If nobody objects
    it, I'll remove them.

Thanks,
-- 
kou

---

From: "David G. Johnston" <[email-masked]>
Date: Mon, 31 Mar 2025 10:05:34 -0700

> > +        .CopyFromEnd = CopyFromEnd,
In trying to document the current API I'm strongly disliking it.  Namely,
the amount of internal code an extension needs to care about/copy-paste to
create a working handler.

Presently, pg_type defines text and binary I/O routines and the text/csv
formats use the text I/O while binary uses binary I/O - for all
attributes.  The CopyFromInFunc API allows for each attribute to somehow
have its I/O format individualized.  But I don't see how that is practical
or useful, and it adds burden on API users.

I suggest we remove both .CopyFromInFunc and .CopyFromStart/End and add a
property to CopyFromRoutine (.ioMode?) with values of either Copy_IO_Text
or Copy_IO_Binary and then just branch to either:

CopyFromTextLikeInFunc & CopyFromTextLikeStart/End
or
CopyFromBinaryInFunc & CopyFromStart/End

So, in effect, the only method an extension needs to write is converting
to/from the 'serialized' form to the text/binary form (text being near
unanimous).

In a similar manner, the amount of boilerplate within CopyFromOneRow seems
undesirable from an API perspective.

cstate->cur_attname = NameStr(att->attname);
cstate->cur_attval = string;

if (string != NULL)
    nulls[m] = false;

if (cstate->defaults[m])
{
    /* We must have switched into the per-tuple memory context */
    Assert(econtext != NULL);
    Assert(CurrentMemoryContext == econtext->ecxt_per_tuple_memory);

    values[m] = ExecEvalExpr(defexprs[m], econtext, &nulls[m]);
}

/*
    * If ON_ERROR is specified with IGNORE, skip rows with soft errors
    */
else if (!InputFunctionCallSafe(&in_functions[m],
                                string,
                                typioparams[m],
                                att->atttypmod,
                                (Node *) cstate->escontext,
                                &values[m]))
{
    CopyFromSkipErrorRow(cstate);
    return true;
}

cstate->cur_attname = NULL;
cstate->cur_attval = NULL;

It seems to me that CopyFromOneRow could simply produce a *string
collection,
one cell per attribute, and NextCopyFrom could do all of the above on a
for-loop over *string

The pg_type and pg_proc catalogs are not extensible so the API can and
should be limited to
producing the, usually text, values that are ready to be passed into the
text I/O routines and all
the work to find and use types and functions left in the template code.

I haven't looked at COPY TO but I am expecting much the same. The API
should simply receive
the content of the type I/O output routine (binary or text as it dictates)
for each output attribute, by
row, and be expected to take those values and produce a final output from
them.

David J.

---

From: Masahiko Sawada <[email-masked]>
Date: Mon, 31 Mar 2025 11:51:30 -0700

On Sat, Mar 29, 2025 at 9:49 AM David G. Johnston
<[email-masked]> wrote:
> I prefer keeping 0002 and 0004 separate.  In particular, keeping the design choice of "unqualified internal format names ignore search_path" should stand out as its own commit.

What is the point of having separate commits for already-agreed design
choices? I guess that it would make it easier to revert that decision.
But I think it makes more sense that if we agree with "unqualified
internal format names ignore search_path" the original commit includes
that decision and describes it in the commit message. If we want to
change that design based on the discussion later on, we can have a
separate commit that makes that change and has the link to the
discussion.

Regards,

---

From: Masahiko Sawada <[email-masked]>
Date: Mon, 31 Mar 2025 12:35:23 -0700

> required for merging this patch set, I'll do it.

I'm not sure that the regression test queries are categorized in the
same way as in test_ddl_deparse. While the former have separate .sql
files for different types of inputs (valid inputs and invalid inputs
etc.) , which seems finer graind, the latter has .sql files for each
DDL command.

Most of the queries under test_copy_format/sql verifies the input
patterns of the FORMAT option. I find that the regression tests
included in that directory probably should focus on testing new
callback APIs and some regression tests for FORMAT option handling can
be moved into the normal regression test suite (e.g., in copy.sql or a
new file like copy_format.sql). IIUC testing for invalid input
patterns can be done even without creating artificial wrong handler
functions.

> DROP EXTENSION test_copy_format;

I'd like to see in the comment what the tests expect. Taking the
following queries as an example,

it would help readers understand the test case better if we have a
comment like for example:

-- Specify the custom format name without schema. We test if both
-- COPY TO and COPY FROM can find the correct handler function
-- in public schema.

> COPY handler when we dump (COPY TO) and we restore (COPY

I agreed.

> haven't looked into it why...

Sorry, I don't follow that. IIUC test_copy_format extension doesn't
create a handler function in myschema schema, and SQLs in builtin.sql
seem to work as expected (specifying a non-qualified built-in format
unconditionally uses the built-in format).

> Copy{To,From}StateData, right?

Yes. I referred to the wrong one.

> And you suggest that we

I think that csv_mode and binary are used mostly in
ProcessCopyOptions() so probably we can use local variables for that.
I find there are two other places where to use csv_mode:
NextCopyFromRawFields() and CopyToTextLikeStart(). I think we can
simply check the handler function's OID there, or we can define macros
like COPY_FORMAT_IS_TEXT/CSV/BINARY checking the OID and use them
there.

> So, we should provide "flush" API not "end of row" API for

Okay, understood.

> merged patches. In general, distinct enum value names are

Right, but the patches that have already been merged contributed to
speed up COPY commands, but 0001 patch also introduces
copyto_internal.h, which is not used by anyone in a case where the
custom copy format patch is not merged. Without adding
copyto_internal.h changing enum value names less makes sense to me.

> BTW, does the "other patches" include the documentation

I think that when pushing the main custom COPY format patch, we need
to include the documentation changes into it.

Regards,

---

From: "David G. Johnston" <[email-masked]>
Date: Mon, 31 Mar 2025 13:42:16 -0700

On Mon, Mar 31, 2025 at 11:52 AM Masahiko Sawada <[email-masked]>
wrote:

> > I prefer keeping 0002 and 0004 separate.  In particular, keeping the
> design choice of "unqualified internal format names ignore search_path"
> should stand out as its own commit.
>

Fair.  Comment withdrawn.  Though I was referring to the WIP patches; I
figured the final patch would squash this all together in any case.

David J.

---

From: "David G. Johnston" <[email-masked]>
Date: Sun, 6 Apr 2025 09:20:56 -0700

On Sun, Apr 6, 2025 at 4:30 AM jian he <[email-masked]> wrote:

>
> CREATE FUNCTION test_copy_format(internal)
>     RETURNS copy_handler
>     AS 'MODULE_PATHNAME', 'test_copy_format'
>     LANGUAGE C;
> src/backend/commands/copy.c: ProcessCopyOptions
>             if (strcmp(fmt, "text") == 0)
>                  /* default format */ ;
>             else if (strcmp(fmt, "csv") == 0)
>                 opts_out->csv_mode = true;
>             else if (strcmp(fmt, "binary") == 0)
>                 opts_out->binary = true;
>             else
>             {
>                 List       *qualified_format;
>                 ....
>             }
> what if our customized format name is one of "csv", "binary", "text",
> then that ELSE branch will never be reached.
> then our customized format is being shadowed?
>
>
Yes.  The user of your extension can specify a schema name to get access to
your conflicting format name choice but all the existing code out there
that relied on text/csv/binary being the built-in options continue to
behave the same no matter the search_path.

David J.

---

From: Sutou Kouhei <[email-masked]>
Date: Fri, 25 Apr 2025 21:45:34 +0900 (JST)

Hi,

I've updated the patch set. See the attached v40 patch set.

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Wed, 23 Apr 2025 23:44:55 -0700,
  Masahiko Sawada <[email-masked]> wrote:

>> Are the followings correct?
>>
>> 1. Move invalid input patterns in
>>    src/test/modules/test_copy_format/sql/invalid.sql to
>>    src/test/regress/sql/copy.sql as much as possible.
>> 2. Create
>>    src/test/modules/test_copy_format/sql/test_copy_format.sql
>>    and move all contents in existing *.sql to the file.
>> 3. Add comments what the tests expect to
>>    src/test/modules/test_copy_format/sql/test_copy_format.sql.
>> 4. Remove CopyFormatOptions::{binary,csv_mode}.
> 
> Agreed with the above items.

Done except 1. because 1. is removed by 3. in the following
list:

----
>> There are 3 unconfirmed suggested changes for tests in:
>> https://www.postgresql.org/message-id/20250330.113126.433742864258096312.kou%40clear-code.com
>>
>> Here are my opinions for them:
>>
----

0005 is added for 4. Could you squash 0004 ("Use copy
handler for bult-in formats") and 0005 ("Remove
CopyFormatOptions::{binary,csv_mode}") if needed when you
push?

>> 6. Use handler OID for detecting the default built-in format
>>    instead of comparing the given format as string.

Done.

>> 7. Update documentation.

Could someone help this? 0007 is the draft commit for this.

>> There are 3 unconfirmed suggested changes for tests in:
>> https://www.postgresql.org/message-id/20250330.113126.433742864258096312.kou%40clear-code.com
>>
>> Here are my opinions for them:
>>
>> Is the 1. required for "ready for merge"? If so, is there
>> any suggestion? I don't have a strong opinion for it.
>>
>> If there are no more opinions for 2. and 3., I'll remove
>> them.
> 
> Agreed.

1.: I didn't do anything. Because there is no suggestion.

2., 3.: Done.

> I think we would still need some rounds of reviews but the patch is
> getting in good shape.

I hope that this is completed in this year...

Thanks,
-- 
kou
>From a81eb07a4c92b8b34ed6fbe6610c54bb9b3bb2e4 Mon Sep 17 00:00:00 2001
From: Sutou Kouhei <[email-masked]>
Date: Mon, 25 Nov 2024 13:58:33 +0900
Subject: [PATCH v40 1/6] Export CopyDest as private data

This is a preparation to export CopyToStateData as private data.

CopyToStateData depends on CopyDest. So we need to export CopyDest
too.

But CopyDest and CopySource has the same names. So we can't export
CopyDest as-is.

This uses the COPY_DEST_ prefix for CopyDest enum values. CopySource
uses the COPY_FROM_ prefix for consistency.
---
 src/backend/commands/copyfrom.c          |  4 ++--
 src/backend/commands/copyfromparse.c     | 10 ++++----
 src/backend/commands/copyto.c            | 30 ++++++++----------------
 src/include/commands/copyfrom_internal.h |  8 +++----
 src/include/commands/copyto_internal.h   | 28 ++++++++++++++++++++++
 5 files changed, 49 insertions(+), 31 deletions(-)
 create mode 100644 src/include/commands/copyto_internal.h

diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index fbbbc09a97b..b4dad744547 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -1709,7 +1709,7 @@ BeginCopyFrom(ParseState *pstate,
 							pg_encoding_to_char(GetDatabaseEncoding()))));
 	}
 
-	cstate->copy_src = COPY_FILE;	/* default */
+	cstate->copy_src = COPY_SOURCE_FILE;	/* default */
 
 	cstate->whereClause = whereClause;
 
@@ -1837,7 +1837,7 @@ BeginCopyFrom(ParseState *pstate,
 	if (data_source_cb)
 	{
 		progress_vals[1] = PROGRESS_COPY_TYPE_CALLBACK;
-		cstate->copy_src = COPY_CALLBACK;
+		cstate->copy_src = COPY_SOURCE_CALLBACK;
 		cstate->data_source_cb = data_source_cb;
 	}
 	else if (pipe)
diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index f5fc346e201..9f7171d1478 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -180,7 +180,7 @@ ReceiveCopyBegin(CopyFromState cstate)
 	for (i = 0; i < natts; i++)
 		pq_sendint16(&buf, format); /* per-column formats */
 	pq_endmessage(&buf);
-	cstate->copy_src = COPY_FRONTEND;
+	cstate->copy_src = COPY_SOURCE_FRONTEND;
 	cstate->fe_msgbuf = makeStringInfo();
 	/* We *must* flush here to ensure FE knows it can send. */
 	pq_flush();
@@ -248,7 +248,7 @@ CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
 
 	switch (cstate->copy_src)
 	{
-		case COPY_FILE:
+		case COPY_SOURCE_FILE:
 			bytesread = fread(databuf, 1, maxread, cstate->copy_file);
 			if (ferror(cstate->copy_file))
 				ereport(ERROR,
@@ -257,7 +257,7 @@ CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
 			if (bytesread == 0)
 				cstate->raw_reached_eof = true;
 			break;
-		case COPY_FRONTEND:
+		case COPY_SOURCE_FRONTEND:
 			while (maxread > 0 && bytesread < minread && !cstate->raw_reached_eof)
 			{
 				int			avail;
@@ -340,7 +340,7 @@ CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
 				bytesread += avail;
 			}
 			break;
-		case COPY_CALLBACK:
+		case COPY_SOURCE_CALLBACK:
 			bytesread = cstate->data_source_cb(databuf, minread, maxread);
 			break;
 	}
@@ -1172,7 +1172,7 @@ CopyReadLine(CopyFromState cstate, bool is_csv)
 		 * after \. up to the protocol end of copy data.  (XXX maybe better
 		 * not to treat \. as special?)
 		 */
-		if (cstate->copy_src == COPY_FRONTEND)
+		if (cstate->copy_src == COPY_SOURCE_FRONTEND)
 		{
 			int			inbytes;
 
diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index f87e405351d..d739826afbc 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -20,6 +20,7 @@
 
 #include "access/tableam.h"
 #include "commands/copyapi.h"
+#include "commands/copyto_internal.h"
 #include "commands/progress.h"
 #include "executor/execdesc.h"
 #include "executor/executor.h"
@@ -36,17 +37,6 @@
 #include "utils/rel.h"
 #include "utils/snapmgr.h"
 
-/*
- * Represents the different dest cases we need to worry about at
- * the bottom level
- */
-typedef enum CopyDest
-{
-	COPY_FILE,					/* to file (or a piped program) */
-	COPY_FRONTEND,				/* to frontend */
-	COPY_CALLBACK,				/* to callback function */
-} CopyDest;
-
 /*
  * This struct contains all the state variables used throughout a COPY TO
  * operation.
@@ -69,7 +59,7 @@ typedef struct CopyToStateData
 
 	/* low-level state data */
 	CopyDest	copy_dest;		/* type of copy source/destination */
-	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
+	FILE	   *copy_file;		/* used if copy_dest == COPY_DEST_FILE */
 	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO */
 
 	int			file_encoding;	/* file or remote side's character encoding */
@@ -401,7 +391,7 @@ SendCopyBegin(CopyToState cstate)
 	for (i = 0; i < natts; i++)
 		pq_sendint16(&buf, format); /* per-column formats */
 	pq_endmessage(&buf);
-	cstate->copy_dest = COPY_FRONTEND;
+	cstate->copy_dest = COPY_DEST_FRONTEND;
 }
 
 static void
@@ -448,7 +438,7 @@ CopySendEndOfRow(CopyToState cstate)
 
 	switch (cstate->copy_dest)
 	{
-		case COPY_FILE:
+		case COPY_DEST_FILE:
 			if (fwrite(fe_msgbuf->data, fe_msgbuf->len, 1,
 					   cstate->copy_file) != 1 ||
 				ferror(cstate->copy_file))
@@ -482,11 +472,11 @@ CopySendEndOfRow(CopyToState cstate)
 							 errmsg("could not write to COPY file: %m")));
 			}
 			break;
-		case COPY_FRONTEND:
+		case COPY_DEST_FRONTEND:
 			/* Dump the accumulated row as one CopyData message */
 			(void) pq_putmessage(PqMsg_CopyData, fe_msgbuf->data, fe_msgbuf->len);
 			break;
-		case COPY_CALLBACK:
+		case COPY_DEST_CALLBACK:
 			cstate->data_dest_cb(fe_msgbuf->data, fe_msgbuf->len);
 			break;
 	}
@@ -507,7 +497,7 @@ CopySendTextLikeEndOfRow(CopyToState cstate)
 {
 	switch (cstate->copy_dest)
 	{
-		case COPY_FILE:
+		case COPY_DEST_FILE:
 			/* Default line termination depends on platform */
 #ifndef WIN32
 			CopySendChar(cstate, '\n');
@@ -515,7 +505,7 @@ CopySendTextLikeEndOfRow(CopyToState cstate)
 			CopySendString(cstate, "\r\n");
 #endif
 			break;
-		case COPY_FRONTEND:
+		case COPY_DEST_FRONTEND:
 			/* The FE/BE protocol uses \n as newline for all platforms */
 			CopySendChar(cstate, '\n');
 			break;
@@ -903,12 +893,12 @@ BeginCopyTo(ParseState *pstate,
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
 
-	cstate->copy_dest = COPY_FILE;	/* default */
+	cstate->copy_dest = COPY_DEST_FILE; /* default */
 
 	if (data_dest_cb)
 	{
 		progress_vals[1] = PROGRESS_COPY_TYPE_CALLBACK;
-		cstate->copy_dest = COPY_CALLBACK;
+		cstate->copy_dest = COPY_DEST_CALLBACK;
 		cstate->data_dest_cb = data_dest_cb;
 	}
 	else if (pipe)
diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h
index c8b22af22d8..24157e11a73 100644
--- a/src/include/commands/copyfrom_internal.h
+++ b/src/include/commands/copyfrom_internal.h
@@ -24,9 +24,9 @@
  */
 typedef enum CopySource
 {
-	COPY_FILE,					/* from file (or a piped program) */
-	COPY_FRONTEND,				/* from frontend */
-	COPY_CALLBACK,				/* from callback function */
+	COPY_SOURCE_FILE,			/* from file (or a piped program) */
+	COPY_SOURCE_FRONTEND,		/* from frontend */
+	COPY_SOURCE_CALLBACK,		/* from callback function */
 } CopySource;
 
 /*
@@ -64,7 +64,7 @@ typedef struct CopyFromStateData
 	/* low-level state data */
 	CopySource	copy_src;		/* type of copy source */
 	FILE	   *copy_file;		/* used if copy_src == COPY_FILE */
-	StringInfo	fe_msgbuf;		/* used if copy_src == COPY_FRONTEND */
+	StringInfo	fe_msgbuf;		/* used if copy_src == COPY_SOURCE_FRONTEND */
 
 	EolType		eol_type;		/* EOL type of input */
 	int			file_encoding;	/* file or remote side's character encoding */
diff --git a/src/include/commands/copyto_internal.h b/src/include/commands/copyto_internal.h
new file mode 100644
index 00000000000..42ddb37a8a2
--- /dev/null
+++ b/src/include/commands/copyto_internal.h
@@ -0,0 +1,28 @@
+/*-------------------------------------------------------------------------
+ *
+ * copyto_internal.h
+ *	  Internal definitions for COPY TO command.
+ *
+ *
+ * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/commands/copyto_internal.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef COPYTO_INTERNAL_H
+#define COPYTO_INTERNAL_H
+
+/*
+ * Represents the different dest cases we need to worry about at
+ * the bottom level
+ */
+typedef enum CopyDest
+{
+	COPY_DEST_FILE,				/* to file (or a piped program) */
+	COPY_DEST_FRONTEND,			/* to frontend */
+	COPY_DEST_CALLBACK,			/* to callback function */
+} CopyDest;
+
+#endif							/* COPYTO_INTERNAL_H */
-- 
2.47.2

>From 398994b555e3b508ce26fc33199bf9badbfc82d5 Mon Sep 17 00:00:00 2001
From: Sutou Kouhei <[email-masked]>
Date: Thu, 27 Mar 2025 11:14:43 +0900
Subject: [PATCH v40 2/6] Add support for adding custom COPY format

This uses the handler approach like tablesample. The approach creates
an internal function that returns an internal struct. In this case,
a handler returns a CopyToRoutine for COPY TO and a CopyFromRoutine
for COPY FROM.

Whether COPY TO or COPY FROM is passed as the "is_from" argument:

    copy_handler(true) returns CopyToRoutine
    copy_handler(false) returns CopyFromRoutine

This also add a test module for custom COPY handler.
---
 src/backend/commands/copy.c                   |  31 ++++-
 src/backend/commands/copyfrom.c               |  20 +++-
 src/backend/commands/copyto.c                 |  72 +++--------
 src/backend/nodes/Makefile                    |   1 +
 src/backend/nodes/gen_node_support.pl         |   2 +
 src/backend/utils/adt/pseudotypes.c           |   1 +
 src/include/catalog/pg_proc.dat               |   6 +
 src/include/catalog/pg_type.dat               |   6 +
 src/include/commands/copy.h                   |   3 +-
 src/include/commands/copyapi.h                |   4 +
 src/include/commands/copyto_internal.h        |  55 +++++++++
 src/include/nodes/meson.build                 |   1 +
 src/test/modules/Makefile                     |   1 +
 src/test/modules/meson.build                  |   1 +
 src/test/modules/test_copy_format/.gitignore  |   4 +
 src/test/modules/test_copy_format/Makefile    |  23 ++++
 .../expected/test_copy_format.out             | 107 +++++++++++++++++
 src/test/modules/test_copy_format/meson.build |  33 +++++
 .../test_copy_format/sql/test_copy_format.sql |  52 ++++++++
 .../test_copy_format--1.0.sql                 |  24 ++++
 .../test_copy_format/test_copy_format.c       | 113 ++++++++++++++++++
 .../test_copy_format/test_copy_format.control |   4 +
 22 files changed, 505 insertions(+), 59 deletions(-)
 mode change 100644 => 100755 src/backend/nodes/gen_node_support.pl
 create mode 100644 src/test/modules/test_copy_format/.gitignore
 create mode 100644 src/test/modules/test_copy_format/Makefile
 create mode 100644 src/test/modules/test_copy_format/expected/test_copy_format.out
 create mode 100644 src/test/modules/test_copy_format/meson.build
 create mode 100644 src/test/modules/test_copy_format/sql/test_copy_format.sql
 create mode 100644 src/test/modules/test_copy_format/test_copy_format--1.0.sql
 create mode 100644 src/test/modules/test_copy_format/test_copy_format.c
 create mode 100644 src/test/modules/test_copy_format/test_copy_format.control

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 74ae42b19a7..9515c4d5786 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -32,10 +32,12 @@
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
+#include "parser/parse_func.h"
 #include "parser/parse_relation.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
+#include "utils/regproc.h"
 #include "utils/rel.h"
 #include "utils/rls.h"
 
@@ -531,10 +533,31 @@ ProcessCopyOptions(ParseState *pstate,
 			else if (strcmp(fmt, "binary") == 0)
 				opts_out->binary = true;
 			else
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("COPY format \"%s\" not recognized", fmt),
-						 parser_errposition(pstate, defel->location)));
+			{
+				List	   *qualified_format;
+				Oid			arg_types[1];
+				Oid			handler = InvalidOid;
+
+				qualified_format = stringToQualifiedNameList(fmt, NULL);
+				arg_types[0] = INTERNALOID;
+				handler = LookupFuncName(qualified_format, 1,
+										 arg_types, true);
+				if (!OidIsValid(handler))
+					ereport(ERROR,
+							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+							 errmsg("COPY format \"%s\" not recognized", fmt),
+							 parser_errposition(pstate, defel->location)));
+
+				/* check that handler has correct return type */
+				if (get_func_rettype(handler) != COPY_HANDLEROID)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("function %s must return type %s",
+									fmt, "copy_handler"),
+							 parser_errposition(pstate, defel->location)));
+
+				opts_out->handler = handler;
+			}
 		}
 		else if (strcmp(defel->defname, "freeze") == 0)
 		{
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index b4dad744547..3d86e8a8328 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -129,6 +129,7 @@ static void CopyFromBinaryEnd(CopyFromState cstate);
 
 /* text format */
 static const CopyFromRoutine CopyFromRoutineText = {
+	.type = T_CopyFromRoutine,
 	.CopyFromInFunc = CopyFromTextLikeInFunc,
 	.CopyFromStart = CopyFromTextLikeStart,
 	.CopyFromOneRow = CopyFromTextOneRow,
@@ -137,6 +138,7 @@ static const CopyFromRoutine CopyFromRoutineText = {
 
 /* CSV format */
 static const CopyFromRoutine CopyFromRoutineCSV = {
+	.type = T_CopyFromRoutine,
 	.CopyFromInFunc = CopyFromTextLikeInFunc,
 	.CopyFromStart = CopyFromTextLikeStart,
 	.CopyFromOneRow = CopyFromCSVOneRow,
@@ -145,6 +147,7 @@ static const CopyFromRoutine CopyFromRoutineCSV = {
 
 /* binary format */
 static const CopyFromRoutine CopyFromRoutineBinary = {
+	.type = T_CopyFromRoutine,
 	.CopyFromInFunc = CopyFromBinaryInFunc,
 	.CopyFromStart = CopyFromBinaryStart,
 	.CopyFromOneRow = CopyFromBinaryOneRow,
@@ -155,7 +158,22 @@ static const CopyFromRoutine CopyFromRoutineBinary = {
 static const CopyFromRoutine *
 CopyFromGetRoutine(const CopyFormatOptions *opts)
 {
-	if (opts->csv_mode)
+	if (OidIsValid(opts->handler))
+	{
+		Datum		datum;
+		Node	   *routine;
+
+		datum = OidFunctionCall1(opts->handler, BoolGetDatum(true));
+		routine = (Node *) DatumGetPointer(datum);
+		if (routine == NULL || !IsA(routine, CopyFromRoutine))
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("COPY handler function %s.%s did not return CopyFromRoutine struct",
+							get_namespace_name(get_func_namespace(opts->handler)),
+							get_func_name(opts->handler))));
+		return castNode(CopyFromRoutine, routine);
+	}
+	else if (opts->csv_mode)
 		return &CopyFromRoutineCSV;
 	else if (opts->binary)
 		return &CopyFromRoutineBinary;
diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index d739826afbc..265b847e255 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -22,9 +22,7 @@
 #include "commands/copyapi.h"
 #include "commands/copyto_internal.h"
 #include "commands/progress.h"
-#include "executor/execdesc.h"
 #include "executor/executor.h"
-#include "executor/tuptable.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
 #include "mb/pg_wchar.h"
@@ -37,56 +35,6 @@
 #include "utils/rel.h"
 #include "utils/snapmgr.h"
 
-/*
- * This struct contains all the state variables used throughout a COPY TO
- * operation.
- *
- * Multi-byte encodings: all supported client-side encodings encode multi-byte
- * characters by having the first byte's high bit set. Subsequent bytes of the
- * character can have the high bit not set. When scanning data in such an
- * encoding to look for a match to a single-byte (ie ASCII) character, we must
- * use the full pg_encoding_mblen() machinery to skip over multibyte
- * characters, else we might find a false match to a trailing byte. In
- * supported server encodings, there is no possibility of a false match, and
- * it's faster to make useless comparisons to trailing bytes than it is to
- * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
- * when we have to do it the hard way.
- */
-typedef struct CopyToStateData
-{
-	/* format-specific routines */
-	const CopyToRoutine *routine;
-
-	/* low-level state data */
-	CopyDest	copy_dest;		/* type of copy source/destination */
-	FILE	   *copy_file;		/* used if copy_dest == COPY_DEST_FILE */
-	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO */
-
-	int			file_encoding;	/* file or remote side's character encoding */
-	bool		need_transcoding;	/* file encoding diff from server? */
-	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
-
-	/* parameters from the COPY command */
-	Relation	rel;			/* relation to copy to */
-	QueryDesc  *queryDesc;		/* executable query to copy from */
-	List	   *attnumlist;		/* integer list of attnums to copy */
-	char	   *filename;		/* filename, or NULL for STDOUT */
-	bool		is_program;		/* is 'filename' a program to popen? */
-	copy_data_dest_cb data_dest_cb; /* function for writing data */
-
-	CopyFormatOptions opts;
-	Node	   *whereClause;	/* WHERE condition (or NULL) */
-
-	/*
-	 * Working state
-	 */
-	MemoryContext copycontext;	/* per-copy execution context */
-
-	FmgrInfo   *out_functions;	/* lookup info for output functions */
-	MemoryContext rowcontext;	/* per-row evaluation context */
-	uint64		bytes_processed;	/* number of bytes processed so far */
-} CopyToStateData;
-
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -140,6 +88,7 @@ static void CopySendInt16(CopyToState cstate, int16 val);
 
 /* text format */
 static const CopyToRoutine CopyToRoutineText = {
+	.type = T_CopyToRoutine,
 	.CopyToStart = CopyToTextLikeStart,
 	.CopyToOutFunc = CopyToTextLikeOutFunc,
 	.CopyToOneRow = CopyToTextOneRow,
@@ -148,6 +97,7 @@ static const CopyToRoutine CopyToRoutineText = {
 
 /* CSV format */
 static const CopyToRoutine CopyToRoutineCSV = {
+	.type = T_CopyToRoutine,
 	.CopyToStart = CopyToTextLikeStart,
 	.CopyToOutFunc = CopyToTextLikeOutFunc,
 	.CopyToOneRow = CopyToCSVOneRow,
@@ -156,6 +106,7 @@ static const CopyToRoutine CopyToRoutineCSV = {
 
 /* binary format */
 static const CopyToRoutine CopyToRoutineBinary = {
+	.type = T_CopyToRoutine,
 	.CopyToStart = CopyToBinaryStart,
 	.CopyToOutFunc = CopyToBinaryOutFunc,
 	.CopyToOneRow = CopyToBinaryOneRow,
@@ -166,7 +117,22 @@ static const CopyToRoutine CopyToRoutineBinary = {
 static const CopyToRoutine *
 CopyToGetRoutine(const CopyFormatOptions *opts)
 {
-	if (opts->csv_mode)
+	if (OidIsValid(opts->handler))
+	{
+		Datum		datum;
+		Node	   *routine;
+
+		datum = OidFunctionCall1(opts->handler, BoolGetDatum(false));
+		routine = (Node *) DatumGetPointer(datum);
+		if (routine == NULL || !IsA(routine, CopyToRoutine))
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("COPY handler function %s.%s did not return CopyToRoutine struct",
+							get_namespace_name(get_func_namespace(opts->handler)),
+							get_func_name(opts->handler))));
+		return castNode(CopyToRoutine, routine);
+	}
+	else if (opts->csv_mode)
 		return &CopyToRoutineCSV;
 	else if (opts->binary)
 		return &CopyToRoutineBinary;
diff --git a/src/backend/nodes/Makefile b/src/backend/nodes/Makefile
index 77ddb9ca53f..dc6c1087361 100644
--- a/src/backend/nodes/Makefile
+++ b/src/backend/nodes/Makefile
@@ -50,6 +50,7 @@ node_headers = \
 	access/sdir.h \
 	access/tableam.h \
 	access/tsmapi.h \
+	commands/copyapi.h \
 	commands/event_trigger.h \
 	commands/trigger.h \
 	executor/tuptable.h \
diff --git a/src/backend/nodes/gen_node_support.pl b/src/backend/nodes/gen_node_support.pl
old mode 100644
new mode 100755
index 77659b0f760..d688bbea3a0
--- a/src/backend/nodes/gen_node_support.pl
+++ b/src/backend/nodes/gen_node_support.pl
@@ -62,6 +62,7 @@ my @all_input_files = qw(
   access/sdir.h
   access/tableam.h
   access/tsmapi.h
+  commands/copyapi.h
   commands/event_trigger.h
   commands/trigger.h
   executor/tuptable.h
@@ -86,6 +87,7 @@ my @nodetag_only_files = qw(
   access/sdir.h
   access/tableam.h
   access/tsmapi.h
+  commands/copyapi.h
   commands/event_trigger.h
   commands/trigger.h
   executor/tuptable.h
diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c
index 317a1f2b282..f2ebc21ca56 100644
--- a/src/backend/utils/adt/pseudotypes.c
+++ b/src/backend/utils/adt/pseudotypes.c
@@ -370,6 +370,7 @@ PSEUDOTYPE_DUMMY_IO_FUNCS(fdw_handler);
 PSEUDOTYPE_DUMMY_IO_FUNCS(table_am_handler);
 PSEUDOTYPE_DUMMY_IO_FUNCS(index_am_handler);
 PSEUDOTYPE_DUMMY_IO_FUNCS(tsm_handler);
+PSEUDOTYPE_DUMMY_IO_FUNCS(copy_handler);
 PSEUDOTYPE_DUMMY_IO_FUNCS(internal);
 PSEUDOTYPE_DUMMY_IO_FUNCS(anyelement);
 PSEUDOTYPE_DUMMY_IO_FUNCS(anynonarray);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 62beb71da28..ba46bfa48a8 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7888,6 +7888,12 @@
 { oid => '3312', descr => 'I/O',
   proname => 'tsm_handler_out', prorettype => 'cstring',
   proargtypes => 'tsm_handler', prosrc => 'tsm_handler_out' },
+{ oid => '8753', descr => 'I/O',
+  proname => 'copy_handler_in', proisstrict => 'f', prorettype => 'copy_handler',
+  proargtypes => 'cstring', prosrc => 'copy_handler_in' },
+{ oid => '8754', descr => 'I/O',
+  proname => 'copy_handler_out', prorettype => 'cstring',
+  proargtypes => 'copy_handler', prosrc => 'copy_handler_out' },
 { oid => '267', descr => 'I/O',
   proname => 'table_am_handler_in', proisstrict => 'f',
   prorettype => 'table_am_handler', proargtypes => 'cstring',
diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat
index 6dca77e0a22..bddf9fb4fbe 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -633,6 +633,12 @@
   typcategory => 'P', typinput => 'tsm_handler_in',
   typoutput => 'tsm_handler_out', typreceive => '-', typsend => '-',
   typalign => 'i' },
+{ oid => '8752',
+  descr => 'pseudo-type for the result of a COPY TO/FROM handler function',
+  typname => 'copy_handler', typlen => '4', typbyval => 't', typtype => 'p',
+  typcategory => 'P', typinput => 'copy_handler_in',
+  typoutput => 'copy_handler_out', typreceive => '-', typsend => '-',
+  typalign => 'i' },
 { oid => '269',
   descr => 'pseudo-type for the result of a table AM handler function',
   typname => 'table_am_handler', typlen => '4', typbyval => 't', typtype => 'p',
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index 06dfdfef721..6df1f8a3b9b 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -87,9 +87,10 @@ typedef struct CopyFormatOptions
 	CopyLogVerbosityChoice log_verbosity;	/* verbosity of logged messages */
 	int64		reject_limit;	/* maximum tolerable number of errors */
 	List	   *convert_select; /* list of column names (can be NIL) */
+	Oid			handler;		/* handler function for custom format routine */
 } CopyFormatOptions;
 
-/* These are private in commands/copy[from|to].c */
+/* These are private in commands/copy[from|to]_internal.h */
 typedef struct CopyFromStateData *CopyFromState;
 typedef struct CopyToStateData *CopyToState;
 
diff --git a/src/include/commands/copyapi.h b/src/include/commands/copyapi.h
index 2a2d2f9876b..53ad3337f86 100644
--- a/src/include/commands/copyapi.h
+++ b/src/include/commands/copyapi.h
@@ -22,6 +22,8 @@
  */
 typedef struct CopyToRoutine
 {
+	NodeTag		type;
+
 	/*
 	 * Set output function information. This callback is called once at the
 	 * beginning of COPY TO.
@@ -60,6 +62,8 @@ typedef struct CopyToRoutine
  */
 typedef struct CopyFromRoutine
 {
+	NodeTag		type;
+
 	/*
 	 * Set input function information. This callback is called once at the
 	 * beginning of COPY FROM.
diff --git a/src/include/commands/copyto_internal.h b/src/include/commands/copyto_internal.h
index 42ddb37a8a2..da796131988 100644
--- a/src/include/commands/copyto_internal.h
+++ b/src/include/commands/copyto_internal.h
@@ -14,6 +14,11 @@
 #ifndef COPYTO_INTERNAL_H
 #define COPYTO_INTERNAL_H
 
+#include "commands/copy.h"
+#include "executor/execdesc.h"
+#include "executor/tuptable.h"
+#include "nodes/execnodes.h"
+
 /*
  * Represents the different dest cases we need to worry about at
  * the bottom level
@@ -25,4 +30,54 @@ typedef enum CopyDest
 	COPY_DEST_CALLBACK,			/* to callback function */
 } CopyDest;
 
+/*
+ * This struct contains all the state variables used throughout a COPY TO
+ * operation.
+ *
+ * Multi-byte encodings: all supported client-side encodings encode multi-byte
+ * characters by having the first byte's high bit set. Subsequent bytes of the
+ * character can have the high bit not set. When scanning data in such an
+ * encoding to look for a match to a single-byte (ie ASCII) character, we must
+ * use the full pg_encoding_mblen() machinery to skip over multibyte
+ * characters, else we might find a false match to a trailing byte. In
+ * supported server encodings, there is no possibility of a false match, and
+ * it's faster to make useless comparisons to trailing bytes than it is to
+ * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
+ * when we have to do it the hard way.
+ */
+typedef struct CopyToStateData
+{
+	/* format-specific routines */
+	const CopyToRoutine *routine;
+
+	/* low-level state data */
+	CopyDest	copy_dest;		/* type of copy source/destination */
+	FILE	   *copy_file;		/* used if copy_dest == COPY_DEST_FILE */
+	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO */
+
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	Relation	rel;			/* relation to copy to */
+	QueryDesc  *queryDesc;		/* executable query to copy from */
+	List	   *attnumlist;		/* integer list of attnums to copy */
+	char	   *filename;		/* filename, or NULL for STDOUT */
+	bool		is_program;		/* is 'filename' a program to popen? */
+	copy_data_dest_cb data_dest_cb; /* function for writing data */
+
+	CopyFormatOptions opts;
+	Node	   *whereClause;	/* WHERE condition (or NULL) */
+
+	/*
+	 * Working state
+	 */
+	MemoryContext copycontext;	/* per-copy execution context */
+
+	FmgrInfo   *out_functions;	/* lookup info for output functions */
+	MemoryContext rowcontext;	/* per-row evaluation context */
+	uint64		bytes_processed;	/* number of bytes processed so far */
+} CopyToStateData;
+
 #endif							/* COPYTO_INTERNAL_H */
diff --git a/src/include/nodes/meson.build b/src/include/nodes/meson.build
index d1ca24dd32f..96e70e7f38b 100644
--- a/src/include/nodes/meson.build
+++ b/src/include/nodes/meson.build
@@ -12,6 +12,7 @@ node_support_input_i = [
   'access/sdir.h',
   'access/tableam.h',
   'access/tsmapi.h',
+  'commands/copyapi.h',
   'commands/event_trigger.h',
   'commands/trigger.h',
   'executor/tuptable.h',
diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile
index aa1d27bbed3..9bf5d58cdae 100644
--- a/src/test/modules/Makefile
+++ b/src/test/modules/Makefile
@@ -17,6 +17,7 @@ SUBDIRS = \
 		  test_aio \
 		  test_bloomfilter \
 		  test_copy_callbacks \
+		  test_copy_format \
 		  test_custom_rmgrs \
 		  test_ddl_deparse \
 		  test_dsa \
diff --git a/src/test/modules/meson.build b/src/test/modules/meson.build
index 9de0057bd1d..5fd06de2737 100644
--- a/src/test/modules/meson.build
+++ b/src/test/modules/meson.build
@@ -16,6 +16,7 @@ subdir('ssl_passphrase_callback')
 subdir('test_aio')
 subdir('test_bloomfilter')
 subdir('test_copy_callbacks')
+subdir('test_copy_format')
 subdir('test_custom_rmgrs')
 subdir('test_ddl_deparse')
 subdir('test_dsa')
diff --git a/src/test/modules/test_copy_format/.gitignore b/src/test/modules/test_copy_format/.gitignore
new file mode 100644
index 00000000000..5dcb3ff9723
--- /dev/null
+++ b/src/test/modules/test_copy_format/.gitignore
@@ -0,0 +1,4 @@
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
diff --git a/src/test/modules/test_copy_format/Makefile b/src/test/modules/test_copy_format/Makefile
new file mode 100644
index 00000000000..8497f91624d
--- /dev/null
+++ b/src/test/modules/test_copy_format/Makefile
@@ -0,0 +1,23 @@
+# src/test/modules/test_copy_format/Makefile
+
+MODULE_big = test_copy_format
+OBJS = \
+	$(WIN32RES) \
+	test_copy_format.o
+PGFILEDESC = "test_copy_format - test custom COPY FORMAT"
+
+EXTENSION = test_copy_format
+DATA = test_copy_format--1.0.sql
+
+REGRESS = test_copy_format
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_copy_format
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/test_copy_format/expected/test_copy_format.out b/src/test/modules/test_copy_format/expected/test_copy_format.out
new file mode 100644
index 00000000000..3916b766615
--- /dev/null
+++ b/src/test/modules/test_copy_format/expected/test_copy_format.out
@@ -0,0 +1,107 @@
+CREATE TABLE copy_data (a smallint, b integer, c bigint);
+INSERT INTO copy_data VALUES (1, 2, 3), (12, 34, 56), (123, 456, 789);
+-- No WITH SCHEMA. It installs custom COPY handlers to the current
+-- schema.
+CREATE EXTENSION test_copy_format;
+-- We can find a custom COPY handler without schema.
+COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format');
+NOTICE:  test_copy_format: is_from=true
+NOTICE:  CopyFromInFunc: attribute: smallint
+NOTICE:  CopyFromInFunc: attribute: integer
+NOTICE:  CopyFromInFunc: attribute: bigint
+NOTICE:  CopyFromStart: the number of attributes: 3
+NOTICE:  CopyFromOneRow
+NOTICE:  CopyFromEnd
+COPY copy_data TO stdout WITH (FORMAT 'test_copy_format');
+NOTICE:  test_copy_format: is_from=false
+NOTICE:  CopyToOutFunc: attribute: smallint
+NOTICE:  CopyToOutFunc: attribute: integer
+NOTICE:  CopyToOutFunc: attribute: bigint
+NOTICE:  CopyToStart: the number of attributes: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToEnd
+DROP EXTENSION test_copy_format;
+-- Install custom COPY handlers to a schema that isn't included in
+-- search_path.
+CREATE SCHEMA test_schema;
+CREATE EXTENSION test_copy_format WITH SCHEMA test_schema;
+-- We can find a custom COPY handler by qualified name.
+COPY copy_data FROM stdin WITH (FORMAT 'test_schema.test_copy_format');
+NOTICE:  test_copy_format: is_from=true
+NOTICE:  CopyFromInFunc: attribute: smallint
+NOTICE:  CopyFromInFunc: attribute: integer
+NOTICE:  CopyFromInFunc: attribute: bigint
+NOTICE:  CopyFromStart: the number of attributes: 3
+NOTICE:  CopyFromOneRow
+NOTICE:  CopyFromEnd
+COPY copy_data TO stdout WITH (FORMAT 'test_schema.test_copy_format');
+NOTICE:  test_copy_format: is_from=false
+NOTICE:  CopyToOutFunc: attribute: smallint
+NOTICE:  CopyToOutFunc: attribute: integer
+NOTICE:  CopyToOutFunc: attribute: bigint
+NOTICE:  CopyToStart: the number of attributes: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToEnd
+-- We can't find a custom COPY handler without schema when search_path
+-- doesn't include the schema where we installed custom COPY handlers.
+COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format');
+ERROR:  COPY format "test_copy_format" not recognized
+LINE 1: COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format');
+                                        ^
+COPY copy_data TO stdout WITH (FORMAT 'test_copy_format');
+ERROR:  COPY format "test_copy_format" not recognized
+LINE 1: COPY copy_data TO stdout WITH (FORMAT 'test_copy_format');
+                                       ^
+-- We can find a custom COPY handler without schema when search_path
+-- includes the schema where we installed custom COPY handlers.
+SET search_path = test_schema,public;
+COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format');
+NOTICE:  test_copy_format: is_from=true
+NOTICE:  CopyFromInFunc: attribute: smallint
+NOTICE:  CopyFromInFunc: attribute: integer
+NOTICE:  CopyFromInFunc: attribute: bigint
+NOTICE:  CopyFromStart: the number of attributes: 3
+NOTICE:  CopyFromOneRow
+NOTICE:  CopyFromEnd
+COPY copy_data TO stdout WITH (FORMAT 'test_copy_format');
+NOTICE:  test_copy_format: is_from=false
+NOTICE:  CopyToOutFunc: attribute: smallint
+NOTICE:  CopyToOutFunc: attribute: integer
+NOTICE:  CopyToOutFunc: attribute: bigint
+NOTICE:  CopyToStart: the number of attributes: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToEnd
+RESET search_path;
+-- Invalid cases with qualified name.
+-- Input type is wrong
+COPY copy_data FROM stdin WITH (FORMAT 'test_schema.test_copy_format_wrong_input_type');
+ERROR:  COPY format "test_schema.test_copy_format_wrong_input_type" not recognized
+LINE 1: COPY copy_data FROM stdin WITH (FORMAT 'test_schema.test_cop...
+                                        ^
+COPY copy_data TO stdout WITH (FORMAT 'test_schema.test_copy_format_wrong_input_type');
+ERROR:  COPY format "test_schema.test_copy_format_wrong_input_type" not recognized
+LINE 1: COPY copy_data TO stdout WITH (FORMAT 'test_schema.test_copy...
+                                       ^
+-- Return type is wrong
+COPY copy_data FROM stdin WITH (FORMAT 'test_schema.test_copy_format_wrong_return_type');
+ERROR:  function test_schema.test_copy_format_wrong_return_type must return type copy_handler
+LINE 1: COPY copy_data FROM stdin WITH (FORMAT 'test_schema.test_cop...
+                                        ^
+COPY copy_data TO stdout WITH (FORMAT 'test_schema.test_copy_format_wrong_return_type');
+ERROR:  function test_schema.test_copy_format_wrong_return_type must return type copy_handler
+LINE 1: COPY copy_data TO stdout WITH (FORMAT 'test_schema.test_copy...
+                                       ^
+-- Returned value is wrong
+COPY copy_data FROM stdin WITH (FORMAT 'test_schema.test_copy_format_wrong_return_value');
+ERROR:  COPY handler function test_schema.test_copy_format_wrong_return_value did not return CopyFromRoutine struct
+COPY copy_data TO stdout WITH (FORMAT 'test_schema.test_copy_format_wrong_return_value');
+ERROR:  COPY handler function test_schema.test_copy_format_wrong_return_value did not return CopyToRoutine struct
+DROP TABLE copy_data;
+DROP EXTENSION test_copy_format;
+DROP SCHEMA test_schema;
diff --git a/src/test/modules/test_copy_format/meson.build b/src/test/modules/test_copy_format/meson.build
new file mode 100644
index 00000000000..a45a2e0a039
--- /dev/null
+++ b/src/test/modules/test_copy_format/meson.build
@@ -0,0 +1,33 @@
+# Copyright (c) 2025, PostgreSQL Global Development Group
+
+test_copy_format_sources = files(
+  'test_copy_format.c',
+)
+
+if host_system == 'windows'
+  test_copy_format_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'test_copy_format',
+    '--FILEDESC', 'test_copy_format - test custom COPY FORMAT',])
+endif
+
+test_copy_format = shared_module('test_copy_format',
+  test_copy_format_sources,
+  kwargs: pg_test_mod_args,
+)
+test_install_libs += test_copy_format
+
+test_install_data += files(
+  'test_copy_format.control',
+  'test_copy_format--1.0.sql',
+)
+
+tests += {
+  'name': 'test_copy_format',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_copy_format',
+    ],
+  },
+}
diff --git a/src/test/modules/test_copy_format/sql/test_copy_format.sql b/src/test/modules/test_copy_format/sql/test_copy_format.sql
new file mode 100644
index 00000000000..b262794f878
--- /dev/null
+++ b/src/test/modules/test_copy_format/sql/test_copy_format.sql
@@ -0,0 +1,52 @@
+CREATE TABLE copy_data (a smallint, b integer, c bigint);
+INSERT INTO copy_data VALUES (1, 2, 3), (12, 34, 56), (123, 456, 789);
+
+-- No WITH SCHEMA. It installs custom COPY handlers to the current
+-- schema.
+CREATE EXTENSION test_copy_format;
+-- We can find a custom COPY handler without schema.
+COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format');
+\.
+COPY copy_data TO stdout WITH (FORMAT 'test_copy_format');
+DROP EXTENSION test_copy_format;
+
+
+-- Install custom COPY handlers to a schema that isn't included in
+-- search_path.
+CREATE SCHEMA test_schema;
+CREATE EXTENSION test_copy_format WITH SCHEMA test_schema;
+
+-- We can find a custom COPY handler by qualified name.
+COPY copy_data FROM stdin WITH (FORMAT 'test_schema.test_copy_format');
+\.
+COPY copy_data TO stdout WITH (FORMAT 'test_schema.test_copy_format');
+
+-- We can't find a custom COPY handler without schema when search_path
+-- doesn't include the schema where we installed custom COPY handlers.
+COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format');
+COPY copy_data TO stdout WITH (FORMAT 'test_copy_format');
+
+-- We can find a custom COPY handler without schema when search_path
+-- includes the schema where we installed custom COPY handlers.
+SET search_path = test_schema,public;
+COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format');
+\.
+COPY copy_data TO stdout WITH (FORMAT 'test_copy_format');
+RESET search_path;
+
+-- Invalid cases with qualified name.
+
+-- Input type is wrong
+COPY copy_data FROM stdin WITH (FORMAT 'test_schema.test_copy_format_wrong_input_type');
+COPY copy_data TO stdout WITH (FORMAT 'test_schema.test_copy_format_wrong_input_type');
+-- Return type is wrong
+COPY copy_data FROM stdin WITH (FORMAT 'test_schema.test_copy_format_wrong_return_type');
+COPY copy_data TO stdout WITH (FORMAT 'test_schema.test_copy_format_wrong_return_type');
+-- Returned value is wrong
+COPY copy_data FROM stdin WITH (FORMAT 'test_schema.test_copy_format_wrong_return_value');
+COPY copy_data TO stdout WITH (FORMAT 'test_schema.test_copy_format_wrong_return_value');
+
+
+DROP TABLE copy_data;
+DROP EXTENSION test_copy_format;
+DROP SCHEMA test_schema;
diff --git a/src/test/modules/test_copy_format/test_copy_format--1.0.sql b/src/test/modules/test_copy_format/test_copy_format--1.0.sql
new file mode 100644
index 00000000000..c1a137181f8
--- /dev/null
+++ b/src/test/modules/test_copy_format/test_copy_format--1.0.sql
@@ -0,0 +1,24 @@
+/* src/test/modules/test_copy_format/test_copy_format--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_copy_format" to load this file. \quit
+
+CREATE FUNCTION test_copy_format(internal)
+	RETURNS copy_handler
+	AS 'MODULE_PATHNAME', 'test_copy_format'
+	LANGUAGE C;
+
+CREATE FUNCTION test_copy_format_wrong_input_type(bool)
+	RETURNS copy_handler
+	AS 'MODULE_PATHNAME', 'test_copy_format'
+	LANGUAGE C;
+
+CREATE FUNCTION test_copy_format_wrong_return_type(internal)
+	RETURNS bool
+	AS 'MODULE_PATHNAME', 'test_copy_format'
+	LANGUAGE C;
+
+CREATE FUNCTION test_copy_format_wrong_return_value(internal)
+	RETURNS copy_handler
+	AS 'MODULE_PATHNAME', 'test_copy_format_wrong_return_value'
+	LANGUAGE C;
diff --git a/src/test/modules/test_copy_format/test_copy_format.c b/src/test/modules/test_copy_format/test_copy_format.c
new file mode 100644
index 00000000000..1d754201336
--- /dev/null
+++ b/src/test/modules/test_copy_format/test_copy_format.c
@@ -0,0 +1,113 @@
+/*--------------------------------------------------------------------------
+ *
+ * test_copy_format.c
+ *		Code for testing custom COPY format.
+ *
+ * Portions Copyright (c) 2025, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *		src/test/modules/test_copy_format/test_copy_format.c
+ *
+ * -------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "commands/copyapi.h"
+#include "commands/defrem.h"
+#include "utils/builtins.h"
+
+PG_MODULE_MAGIC;
+
+static void
+TestCopyFromInFunc(CopyFromState cstate, Oid atttypid,
+				   FmgrInfo *finfo, Oid *typioparam)
+{
+	ereport(NOTICE, (errmsg("CopyFromInFunc: attribute: %s", format_type_be(atttypid))));
+}
+
+static void
+TestCopyFromStart(CopyFromState cstate, TupleDesc tupDesc)
+{
+	ereport(NOTICE, (errmsg("CopyFromStart: the number of attributes: %d", tupDesc->natts)));
+}
+
+static bool
+TestCopyFromOneRow(CopyFromState cstate, ExprContext *econtext, Datum *values, bool *nulls)
+{
+	ereport(NOTICE, (errmsg("CopyFromOneRow")));
+	return false;
+}
+
+static void
+TestCopyFromEnd(CopyFromState cstate)
+{
+	ereport(NOTICE, (errmsg("CopyFromEnd")));
+}
+
+static const CopyFromRoutine CopyFromRoutineTestCopyFormat = {
+	.type = T_CopyFromRoutine,
+	.CopyFromInFunc = TestCopyFromInFunc,
+	.CopyFromStart = TestCopyFromStart,
+	.CopyFromOneRow = TestCopyFromOneRow,
+	.CopyFromEnd = TestCopyFromEnd,
+};
+
+static void
+TestCopyToOutFunc(CopyToState cstate, Oid atttypid, FmgrInfo *finfo)
+{
+	ereport(NOTICE, (errmsg("CopyToOutFunc: attribute: %s", format_type_be(atttypid))));
+}
+
+static void
+TestCopyToStart(CopyToState cstate, TupleDesc tupDesc)
+{
+	ereport(NOTICE, (errmsg("CopyToStart: the number of attributes: %d", tupDesc->natts)));
+}
+
+static void
+TestCopyToOneRow(CopyToState cstate, TupleTableSlot *slot)
+{
+	ereport(NOTICE, (errmsg("CopyToOneRow: the number of valid values: %u", slot->tts_nvalid)));
+}
+
+static void
+TestCopyToEnd(CopyToState cstate)
+{
+	ereport(NOTICE, (errmsg("CopyToEnd")));
+}
+
+static const CopyToRoutine CopyToRoutineTestCopyFormat = {
+	.type = T_CopyToRoutine,
+	.CopyToOutFunc = TestCopyToOutFunc,
+	.CopyToStart = TestCopyToStart,
+	.CopyToOneRow = TestCopyToOneRow,
+	.CopyToEnd = TestCopyToEnd,
+};
+
+PG_FUNCTION_INFO_V1(test_copy_format);
+Datum
+test_copy_format(PG_FUNCTION_ARGS)
+{
+	bool		is_from = PG_GETARG_BOOL(0);
+
+	ereport(NOTICE,
+			(errmsg("test_copy_format: is_from=%s", is_from ? "true" : "false")));
+
+	if (is_from)
+		PG_RETURN_POINTER(&CopyFromRoutineTestCopyFormat);
+	else
+		PG_RETURN_POINTER(&CopyToRoutineTestCopyFormat);
+}
+
+PG_FUNCTION_INFO_V1(test_copy_format_wrong_return_value);
+Datum
+test_copy_format_wrong_return_value(PG_FUNCTION_ARGS)
+{
+	bool		is_from = PG_GETARG_BOOL(0);
+
+	if (is_from)
+		PG_RETURN_CSTRING(pstrdup("is_from=true"));
+	else
+		PG_RETURN_CSTRING(pstrdup("is_from=false"));
+}
diff --git a/src/test/modules/test_copy_format/test_copy_format.control b/src/test/modules/test_copy_format/test_copy_format.control
new file mode 100644
index 00000000000..f05a6362358
--- /dev/null
+++ b/src/test/modules/test_copy_format/test_copy_format.control
@@ -0,0 +1,4 @@
+comment = 'Test code for custom COPY format'
+default_version = '1.0'
+module_pathname = '$libdir/test_copy_format'
+relocatable = true
-- 
2.47.2

>From 18618368721678d78934251ff8243705013458f0 Mon Sep 17 00:00:00 2001
From: Sutou Kouhei <[email-masked]>
Date: Thu, 27 Mar 2025 11:24:15 +0900
Subject: [PATCH v40 3/6] Add support for implementing custom COPY handler as
 extension

* TO: Add CopyToStateData::opaque that can be used to keep
  data for custom COPY TO handler implementation
* TO: Export CopySendEndOfRow() to send end of row data as
  CopyToStateFlush()
* FROM: Add CopyFromStateData::opaque that can be used to
  keep data for custom COPY FROM handler implementation
* FROM: Export CopyGetData() to get the next data as
  CopyFromStateGetData()
* FROM: Add CopyFromSkipErrorRow() for "ON_ERROR stop" and
  "LOG_VERBOSITY verbose"

COPY FROM extensions must call CopyFromSkipErrorRow() when
CopyFromOneRow callback reports an error by
errsave(). CopyFromSkipErrorRow() handles "ON_ERROR stop" and
"LOG_VERBOSITY verbose" cases.
---
 src/backend/commands/copyfromparse.c          | 93 ++++++++++++-------
 src/backend/commands/copyto.c                 | 12 +++
 src/include/commands/copyapi.h                |  6 ++
 src/include/commands/copyfrom_internal.h      |  3 +
 src/include/commands/copyto_internal.h        |  3 +
 .../expected/test_copy_format.out             | 50 ++++++++++
 .../test_copy_format/sql/test_copy_format.sql | 35 +++++++
 .../test_copy_format/test_copy_format.c       | 80 +++++++++++++++-
 8 files changed, 245 insertions(+), 37 deletions(-)

diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index 9f7171d1478..de68b53b000 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -739,6 +739,17 @@ CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes)
 	return copied_bytes;
 }
 
+/*
+ * Export CopyGetData() for extensions. We want to keep CopyGetData() as a
+ * static function for optimization. CopyGetData() calls in this file may be
+ * optimized by a compiler.
+ */
+int
+CopyFromStateGetData(CopyFromState cstate, void *dest, int minread, int maxread)
+{
+	return CopyGetData(cstate, dest, minread, maxread);
+}
+
 /*
  * This function is exposed for use by extensions that read raw fields in the
  * next line. See NextCopyFromRawFieldsInternal() for details.
@@ -927,6 +938,51 @@ CopyFromCSVOneRow(CopyFromState cstate, ExprContext *econtext, Datum *values,
 	return CopyFromTextLikeOneRow(cstate, econtext, values, nulls, true);
 }
 
+/*
+ * Call this when you report an error by errsave() in your CopyFromOneRow
+ * callback. This handles "ON_ERROR stop" and "LOG_VERBOSITY verbose" cases
+ * for you.
+ */
+void
+CopyFromSkipErrorRow(CopyFromState cstate)
+{
+	Assert(cstate->opts.on_error != COPY_ON_ERROR_STOP);
+
+	cstate->num_errors++;
+
+	if (cstate->opts.log_verbosity == COPY_LOG_VERBOSITY_VERBOSE)
+	{
+		/*
+		 * Since we emit line number and column info in the below notice
+		 * message, we suppress error context information other than the
+		 * relation name.
+		 */
+		Assert(!cstate->relname_only);
+		cstate->relname_only = true;
+
+		if (cstate->cur_attval)
+		{
+			char	   *attval;
+
+			attval = CopyLimitPrintoutLength(cstate->cur_attval);
+			ereport(NOTICE,
+					errmsg("skipping row due to data type incompatibility at line %" PRIu64 " for column \"%s\": \"%s\"",
+						   cstate->cur_lineno,
+						   cstate->cur_attname,
+						   attval));
+			pfree(attval);
+		}
+		else
+			ereport(NOTICE,
+					errmsg("skipping row due to data type incompatibility at line %" PRIu64 " for column \"%s\": null input",
+						   cstate->cur_lineno,
+						   cstate->cur_attname));
+
+		/* reset relname_only */
+		cstate->relname_only = false;
+	}
+}
+
 /*
  * Workhorse for CopyFromTextOneRow() and CopyFromCSVOneRow().
  *
@@ -1033,42 +1089,7 @@ CopyFromTextLikeOneRow(CopyFromState cstate, ExprContext *econtext,
 										(Node *) cstate->escontext,
 										&values[m]))
 		{
-			Assert(cstate->opts.on_error != COPY_ON_ERROR_STOP);
-
-			cstate->num_errors++;
-
-			if (cstate->opts.log_verbosity == COPY_LOG_VERBOSITY_VERBOSE)
-			{
-				/*
-				 * Since we emit line number and column info in the below
-				 * notice message, we suppress error context information other
-				 * than the relation name.
-				 */
-				Assert(!cstate->relname_only);
-				cstate->relname_only = true;
-
-				if (cstate->cur_attval)
-				{
-					char	   *attval;
-
-					attval = CopyLimitPrintoutLength(cstate->cur_attval);
-					ereport(NOTICE,
-							errmsg("skipping row due to data type incompatibility at line %" PRIu64 " for column \"%s\": \"%s\"",
-								   cstate->cur_lineno,
-								   cstate->cur_attname,
-								   attval));
-					pfree(attval);
-				}
-				else
-					ereport(NOTICE,
-							errmsg("skipping row due to data type incompatibility at line %" PRIu64 " for column \"%s\": null input",
-								   cstate->cur_lineno,
-								   cstate->cur_attname));
-
-				/* reset relname_only */
-				cstate->relname_only = false;
-			}
-
+			CopyFromSkipErrorRow(cstate);
 			return true;
 		}
 
diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index 265b847e255..d6fcfdfb9b1 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -454,6 +454,18 @@ CopySendEndOfRow(CopyToState cstate)
 	resetStringInfo(fe_msgbuf);
 }
 
+/*
+ * Export CopySendEndOfRow() for extensions. We want to keep
+ * CopySendEndOfRow() as a static function for
+ * optimization. CopySendEndOfRow() calls in this file may be optimized by a
+ * compiler.
+ */
+void
+CopyToStateFlush(CopyToState cstate)
+{
+	CopySendEndOfRow(cstate);
+}
+
 /*
  * Wrapper function of CopySendEndOfRow for text and CSV formats. Sends the
  * line termination and do common appropriate things for the end of row.
diff --git a/src/include/commands/copyapi.h b/src/include/commands/copyapi.h
index 53ad3337f86..500ece7d5bb 100644
--- a/src/include/commands/copyapi.h
+++ b/src/include/commands/copyapi.h
@@ -56,6 +56,8 @@ typedef struct CopyToRoutine
 	void		(*CopyToEnd) (CopyToState cstate);
 } CopyToRoutine;
 
+extern void CopyToStateFlush(CopyToState cstate);
+
 /*
  * API structure for a COPY FROM format implementation. Note this must be
  * allocated in a server-lifetime manner, typically as a static const struct.
@@ -106,4 +108,8 @@ typedef struct CopyFromRoutine
 	void		(*CopyFromEnd) (CopyFromState cstate);
 } CopyFromRoutine;
 
+extern int	CopyFromStateGetData(CopyFromState cstate, void *dest, int minread, int maxread);
+
+extern void CopyFromSkipErrorRow(CopyFromState cstate);
+
 #endif							/* COPYAPI_H */
diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h
index 24157e11a73..f9e27152313 100644
--- a/src/include/commands/copyfrom_internal.h
+++ b/src/include/commands/copyfrom_internal.h
@@ -181,6 +181,9 @@ typedef struct CopyFromStateData
 #define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
 
 	uint64		bytes_processed;	/* number of bytes processed so far */
+
+	/* For custom format implementation */
+	void	   *opaque;			/* private space */
 } CopyFromStateData;
 
 extern void ReceiveCopyBegin(CopyFromState cstate);
diff --git a/src/include/commands/copyto_internal.h b/src/include/commands/copyto_internal.h
index da796131988..3bd9d702bf0 100644
--- a/src/include/commands/copyto_internal.h
+++ b/src/include/commands/copyto_internal.h
@@ -78,6 +78,9 @@ typedef struct CopyToStateData
 	FmgrInfo   *out_functions;	/* lookup info for output functions */
 	MemoryContext rowcontext;	/* per-row evaluation context */
 	uint64		bytes_processed;	/* number of bytes processed so far */
+
+	/* For custom format implementation */
+	void	   *opaque;			/* private space */
 } CopyToStateData;
 
 #endif							/* COPYTO_INTERNAL_H */
diff --git a/src/test/modules/test_copy_format/expected/test_copy_format.out b/src/test/modules/test_copy_format/expected/test_copy_format.out
index 3916b766615..47a875f0ab1 100644
--- a/src/test/modules/test_copy_format/expected/test_copy_format.out
+++ b/src/test/modules/test_copy_format/expected/test_copy_format.out
@@ -4,6 +4,8 @@ INSERT INTO copy_data VALUES (1, 2, 3), (12, 34, 56), (123, 456, 789);
 -- schema.
 CREATE EXTENSION test_copy_format;
 -- We can find a custom COPY handler without schema.
+-- 987 is accepted.
+-- 654 is a hard error because ON_ERROR is stop by default.
 COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format');
 NOTICE:  test_copy_format: is_from=true
 NOTICE:  CopyFromInFunc: attribute: smallint
@@ -11,7 +13,50 @@ NOTICE:  CopyFromInFunc: attribute: integer
 NOTICE:  CopyFromInFunc: attribute: bigint
 NOTICE:  CopyFromStart: the number of attributes: 3
 NOTICE:  CopyFromOneRow
+NOTICE:  CopyFromOneRow
+ERROR:  invalid value: "6"
+CONTEXT:  COPY copy_data, line 2, column a: "6"
+-- 987 is accepted.
+-- 654 is a soft error because ON_ERROR is ignore.
+COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format', ON_ERROR ignore);
+NOTICE:  test_copy_format: is_from=true
+NOTICE:  CopyFromInFunc: attribute: smallint
+NOTICE:  CopyFromInFunc: attribute: integer
+NOTICE:  CopyFromInFunc: attribute: bigint
+NOTICE:  CopyFromStart: the number of attributes: 3
+NOTICE:  CopyFromOneRow
+NOTICE:  CopyFromOneRow
+NOTICE:  CopyFromOneRow
+NOTICE:  1 row was skipped due to data type incompatibility
 NOTICE:  CopyFromEnd
+-- 987 is accepted.
+-- 654 is a soft error because ON_ERROR is ignore.
+COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format', ON_ERROR ignore, LOG_VERBOSITY verbose);
+NOTICE:  test_copy_format: is_from=true
+NOTICE:  CopyFromInFunc: attribute: smallint
+NOTICE:  CopyFromInFunc: attribute: integer
+NOTICE:  CopyFromInFunc: attribute: bigint
+NOTICE:  CopyFromStart: the number of attributes: 3
+NOTICE:  CopyFromOneRow
+NOTICE:  CopyFromOneRow
+NOTICE:  skipping row due to data type incompatibility at line 2 for column "a": "6"
+NOTICE:  CopyFromOneRow
+NOTICE:  1 row was skipped due to data type incompatibility
+NOTICE:  CopyFromEnd
+-- 987 is accepted.
+-- 654 is a soft error because ON_ERROR is ignore.
+-- 321 is a hard error.
+COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format', ON_ERROR ignore);
+NOTICE:  test_copy_format: is_from=true
+NOTICE:  CopyFromInFunc: attribute: smallint
+NOTICE:  CopyFromInFunc: attribute: integer
+NOTICE:  CopyFromInFunc: attribute: bigint
+NOTICE:  CopyFromStart: the number of attributes: 3
+NOTICE:  CopyFromOneRow
+NOTICE:  CopyFromOneRow
+NOTICE:  CopyFromOneRow
+ERROR:  too much lines: 3
+CONTEXT:  COPY copy_data, line 3
 COPY copy_data TO stdout WITH (FORMAT 'test_copy_format');
 NOTICE:  test_copy_format: is_from=false
 NOTICE:  CopyToOutFunc: attribute: smallint
@@ -21,7 +66,12 @@ NOTICE:  CopyToStart: the number of attributes: 3
 NOTICE:  CopyToOneRow: the number of valid values: 3
 NOTICE:  CopyToOneRow: the number of valid values: 3
 NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
 NOTICE:  CopyToEnd
+-- Reset data.
+TRUNCATE copy_data;
+INSERT INTO copy_data VALUES (1, 2, 3), (12, 34, 56), (123, 456, 789);
 DROP EXTENSION test_copy_format;
 -- Install custom COPY handlers to a schema that isn't included in
 -- search_path.
diff --git a/src/test/modules/test_copy_format/sql/test_copy_format.sql b/src/test/modules/test_copy_format/sql/test_copy_format.sql
index b262794f878..c7beb2fb8ae 100644
--- a/src/test/modules/test_copy_format/sql/test_copy_format.sql
+++ b/src/test/modules/test_copy_format/sql/test_copy_format.sql
@@ -4,10 +4,45 @@ INSERT INTO copy_data VALUES (1, 2, 3), (12, 34, 56), (123, 456, 789);
 -- No WITH SCHEMA. It installs custom COPY handlers to the current
 -- schema.
 CREATE EXTENSION test_copy_format;
+
 -- We can find a custom COPY handler without schema.
+
+-- 987 is accepted.
+-- 654 is a hard error because ON_ERROR is stop by default.
 COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format');
+987
+654
 \.
+
+-- 987 is accepted.
+-- 654 is a soft error because ON_ERROR is ignore.
+COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format', ON_ERROR ignore);
+987
+654
+\.
+
+-- 987 is accepted.
+-- 654 is a soft error because ON_ERROR is ignore.
+COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format', ON_ERROR ignore, LOG_VERBOSITY verbose);
+987
+654
+\.
+
+-- 987 is accepted.
+-- 654 is a soft error because ON_ERROR is ignore.
+-- 321 is a hard error.
+COPY copy_data FROM stdin WITH (FORMAT 'test_copy_format', ON_ERROR ignore);
+987
+654
+321
+\.
+
 COPY copy_data TO stdout WITH (FORMAT 'test_copy_format');
+
+-- Reset data.
+TRUNCATE copy_data;
+INSERT INTO copy_data VALUES (1, 2, 3), (12, 34, 56), (123, 456, 789);
+
 DROP EXTENSION test_copy_format;

diff --git a/src/test/modules/test_copy_format/test_copy_format.c b/src/test/modules/test_copy_format/test_copy_format.c
index 1d754201336..34ec693a7ec 100644
--- a/src/test/modules/test_copy_format/test_copy_format.c
+++ b/src/test/modules/test_copy_format/test_copy_format.c
@@ -14,6 +14,7 @@
 #include "postgres.h"
 
 #include "commands/copyapi.h"
+#include "commands/copyfrom_internal.h"
 #include "commands/defrem.h"
 #include "utils/builtins.h"
 
@@ -35,8 +36,85 @@ TestCopyFromStart(CopyFromState cstate, TupleDesc tupDesc)
 static bool
 TestCopyFromOneRow(CopyFromState cstate, ExprContext *econtext, Datum *values, bool *nulls)
 {
+	int			n_attributes = list_length(cstate->attnumlist);
+	char	   *line;
+	int			line_size = n_attributes + 1;	/* +1 is for new line */
+	int			read_bytes;
+
 	ereport(NOTICE, (errmsg("CopyFromOneRow")));
-	return false;
+
+	cstate->cur_lineno++;
+	line = palloc(line_size);
+	read_bytes = CopyFromStateGetData(cstate, line, line_size, line_size);
+	if (read_bytes == 0)
+		return false;
+	if (read_bytes != line_size)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("one line must be %d bytes: %d",
+						line_size, read_bytes)));
+
+	if (cstate->cur_lineno == 1)
+	{
+		/* Success */
+		TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+		ListCell   *cur;
+		int			i = 0;
+
+		foreach(cur, cstate->attnumlist)
+		{
+			int			attnum = lfirst_int(cur);
+			int			m = attnum - 1;
+			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+			if (att->atttypid == INT2OID)
+			{
+				values[i] = Int16GetDatum(line[i] - '0');
+			}
+			else if (att->atttypid == INT4OID)
+			{
+				values[i] = Int32GetDatum(line[i] - '0');
+			}
+			else if (att->atttypid == INT8OID)
+			{
+				values[i] = Int64GetDatum(line[i] - '0');
+			}
+			nulls[i] = false;
+			i++;
+		}
+	}
+	else if (cstate->cur_lineno == 2)
+	{
+		/* Soft error */
+		TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+		int			attnum = lfirst_int(list_head(cstate->attnumlist));
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+		char		value[2];
+
+		cstate->cur_attname = NameStr(att->attname);
+		value[0] = line[0];
+		value[1] = '\0';
+		cstate->cur_attval = value;
+		errsave((Node *) cstate->escontext,
+				(
+				 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				 errmsg("invalid value: \"%c\"", line[0])));
+		CopyFromSkipErrorRow(cstate);
+		cstate->cur_attname = NULL;
+		cstate->cur_attval = NULL;
+		return true;
+	}
+	else
+	{
+		/* Hard error */
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("too much lines: %llu",
+						(unsigned long long) cstate->cur_lineno)));
+	}
+
+	return true;
 }
 
 static void
-- 
2.47.2

>From ed454fd1998bca012182b977c227b4a0caa3ccd6 Mon Sep 17 00:00:00 2001
From: Sutou Kouhei <[email-masked]>
Date: Thu, 27 Mar 2025 11:56:45 +0900
Subject: [PATCH v40 4/6] Use copy handlers for built-in formats

This adds copy handlers for text, csv and binary. We can simplify
Copy{To,From}GetRoutine() by this. We'll be able to remove
CopyFormatOptions::{binary,csv_mode} when we add more callbacks to
Copy{To,From}Routine and move format specific routines to
Copy{To,From}Routine::*.
---
 src/backend/commands/copy.c                   | 101 ++++++++++++------
 src/backend/commands/copyfrom.c               |  42 ++++----
 src/backend/commands/copyto.c                 |  42 ++++----
 src/include/catalog/pg_proc.dat               |  11 ++
 src/include/commands/copy.h                   |   2 +-
 src/include/commands/copyfrom_internal.h      |   6 +-
 src/include/commands/copyto_internal.h        |   6 +-
 .../expected/test_copy_format.out             |  35 ++++++
 .../test_copy_format/sql/test_copy_format.sql |  32 ++++++
 .../test_copy_format--1.0.sql                 |  15 +++
 10 files changed, 211 insertions(+), 81 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 9515c4d5786..38ed8bccacd 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -22,7 +22,9 @@
 #include "access/table.h"
 #include "access/xact.h"
 #include "catalog/pg_authid.h"
-#include "commands/copy.h"
+#include "commands/copyapi.h"
+#include "commands/copyto_internal.h"
+#include "commands/copyfrom_internal.h"
 #include "commands/defrem.h"
 #include "executor/executor.h"
 #include "mb/pg_wchar.h"
@@ -521,43 +523,45 @@ ProcessCopyOptions(ParseState *pstate,
 
 		if (strcmp(defel->defname, "format") == 0)
 		{
-			char	   *fmt = defGetString(defel);
+			char	   *format = defGetString(defel);
+			List	   *qualified_format;
+			char	   *schema;
+			char	   *fmt;
+			Oid			arg_types[1];
+			Oid			handler = InvalidOid;
 
 			if (format_specified)
 				errorConflictingDefElem(defel, pstate);
 			format_specified = true;
-			if (strcmp(fmt, "text") == 0)
-				 /* default format */ ;
-			else if (strcmp(fmt, "csv") == 0)
-				opts_out->csv_mode = true;
-			else if (strcmp(fmt, "binary") == 0)
-				opts_out->binary = true;
-			else
+
+			qualified_format = stringToQualifiedNameList(format, NULL);
+			DeconstructQualifiedName(qualified_format, &schema, &fmt);
+			if (!schema || strcmp(schema, "pg_catalog") == 0)
 			{
-				List	   *qualified_format;
-				Oid			arg_types[1];
-				Oid			handler = InvalidOid;
-
-				qualified_format = stringToQualifiedNameList(fmt, NULL);
-				arg_types[0] = INTERNALOID;
-				handler = LookupFuncName(qualified_format, 1,
-										 arg_types, true);
-				if (!OidIsValid(handler))
-					ereport(ERROR,
-							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-							 errmsg("COPY format \"%s\" not recognized", fmt),
-							 parser_errposition(pstate, defel->location)));
-
-				/* check that handler has correct return type */
-				if (get_func_rettype(handler) != COPY_HANDLEROID)
-					ereport(ERROR,
-							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-							 errmsg("function %s must return type %s",
-									fmt, "copy_handler"),
-							 parser_errposition(pstate, defel->location)));
-
-				opts_out->handler = handler;
+				if (strcmp(fmt, "csv") == 0)
+					opts_out->csv_mode = true;
+				else if (strcmp(fmt, "binary") == 0)
+					opts_out->binary = true;
 			}
+
+			arg_types[0] = INTERNALOID;
+			handler = LookupFuncName(qualified_format, 1,
+									 arg_types, true);
+			if (!OidIsValid(handler))
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("COPY format \"%s\" not recognized", format),
+						 parser_errposition(pstate, defel->location)));
+
+			/* check that handler has correct return type */
+			if (get_func_rettype(handler) != COPY_HANDLEROID)
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("function %s must return type %s",
+								format, "copy_handler"),
+						 parser_errposition(pstate, defel->location)));
+
+			opts_out->handler = handler;
 		}
 		else if (strcmp(defel->defname, "freeze") == 0)
 		{
@@ -1040,3 +1044,36 @@ CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist)
 
 	return attnums;
 }
+
+Datum
+copy_text_handler(PG_FUNCTION_ARGS)
+{
+	bool		is_from = PG_GETARG_BOOL(0);
+
+	if (is_from)
+		PG_RETURN_POINTER(&CopyFromRoutineText);
+	else
+		PG_RETURN_POINTER(&CopyToRoutineText);
+}
+
+Datum
+copy_csv_handler(PG_FUNCTION_ARGS)
+{
+	bool		is_from = PG_GETARG_BOOL(0);
+
+	if (is_from)
+		PG_RETURN_POINTER(&CopyFromRoutineCSV);
+	else
+		PG_RETURN_POINTER(&CopyToRoutineCSV);
+}
+
+Datum
+copy_binary_handler(PG_FUNCTION_ARGS)
+{
+	bool		is_from = PG_GETARG_BOOL(0);
+
+	if (is_from)
+		PG_RETURN_POINTER(&CopyFromRoutineBinary);
+	else
+		PG_RETURN_POINTER(&CopyToRoutineBinary);
+}
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index 3d86e8a8328..74a8051c24c 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -45,6 +45,7 @@
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
 #include "tcop/tcopprot.h"
+#include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/portal.h"
@@ -128,7 +129,7 @@ static void CopyFromBinaryEnd(CopyFromState cstate);
  */
 
 /* text format */
-static const CopyFromRoutine CopyFromRoutineText = {
+const CopyFromRoutine CopyFromRoutineText = {
 	.type = T_CopyFromRoutine,
 	.CopyFromInFunc = CopyFromTextLikeInFunc,
 	.CopyFromStart = CopyFromTextLikeStart,
@@ -137,7 +138,7 @@ static const CopyFromRoutine CopyFromRoutineText = {
 };
 
 /* CSV format */
-static const CopyFromRoutine CopyFromRoutineCSV = {
+const CopyFromRoutine CopyFromRoutineCSV = {
 	.type = T_CopyFromRoutine,
 	.CopyFromInFunc = CopyFromTextLikeInFunc,
 	.CopyFromStart = CopyFromTextLikeStart,
@@ -146,7 +147,7 @@ static const CopyFromRoutine CopyFromRoutineCSV = {
 };
 
 /* binary format */
-static const CopyFromRoutine CopyFromRoutineBinary = {
+const CopyFromRoutine CopyFromRoutineBinary = {
 	.type = T_CopyFromRoutine,
 	.CopyFromInFunc = CopyFromBinaryInFunc,
 	.CopyFromStart = CopyFromBinaryStart,
@@ -158,28 +159,23 @@ static const CopyFromRoutine CopyFromRoutineBinary = {
 static const CopyFromRoutine *
 CopyFromGetRoutine(const CopyFormatOptions *opts)
 {
-	if (OidIsValid(opts->handler))
-	{
-		Datum		datum;
-		Node	   *routine;
-
-		datum = OidFunctionCall1(opts->handler, BoolGetDatum(true));
-		routine = (Node *) DatumGetPointer(datum);
-		if (routine == NULL || !IsA(routine, CopyFromRoutine))
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("COPY handler function %s.%s did not return CopyFromRoutine struct",
-							get_namespace_name(get_func_namespace(opts->handler)),
-							get_func_name(opts->handler))));
-		return castNode(CopyFromRoutine, routine);
-	}
-	else if (opts->csv_mode)
-		return &CopyFromRoutineCSV;
-	else if (opts->binary)
-		return &CopyFromRoutineBinary;
+	Oid			handler = opts->handler;
+	Datum		datum;
+	Node	   *routine;
 
 	/* default is text */
-	return &CopyFromRoutineText;
+	if (!OidIsValid(handler))
+		handler = F_TEXT_INTERNAL;
+
+	datum = OidFunctionCall1(handler, BoolGetDatum(true));
+	routine = (Node *) DatumGetPointer(datum);
+	if (routine == NULL || !IsA(routine, CopyFromRoutine))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("COPY handler function %s.%s did not return CopyFromRoutine struct",
+						get_namespace_name(get_func_namespace(handler)),
+						get_func_name(handler))));
+	return castNode(CopyFromRoutine, routine);
 }
 
 /* Implementation of the start callback for text and CSV formats */
diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index d6fcfdfb9b1..4e1b154cad2 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -30,6 +30,7 @@
 #include "pgstat.h"
 #include "storage/fd.h"
 #include "tcop/tcopprot.h"
+#include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
@@ -87,7 +88,7 @@ static void CopySendInt16(CopyToState cstate, int16 val);
  */
 
 /* text format */
-static const CopyToRoutine CopyToRoutineText = {
+const CopyToRoutine CopyToRoutineText = {
 	.type = T_CopyToRoutine,
 	.CopyToStart = CopyToTextLikeStart,
 	.CopyToOutFunc = CopyToTextLikeOutFunc,
@@ -96,7 +97,7 @@ static const CopyToRoutine CopyToRoutineText = {
 };
 
 /* CSV format */
-static const CopyToRoutine CopyToRoutineCSV = {
+const CopyToRoutine CopyToRoutineCSV = {
 	.type = T_CopyToRoutine,
 	.CopyToStart = CopyToTextLikeStart,
 	.CopyToOutFunc = CopyToTextLikeOutFunc,
@@ -105,7 +106,7 @@ static const CopyToRoutine CopyToRoutineCSV = {
 };
 
 /* binary format */
-static const CopyToRoutine CopyToRoutineBinary = {
+const CopyToRoutine CopyToRoutineBinary = {
 	.type = T_CopyToRoutine,
 	.CopyToStart = CopyToBinaryStart,
 	.CopyToOutFunc = CopyToBinaryOutFunc,
@@ -117,28 +118,23 @@ static const CopyToRoutine CopyToRoutineBinary = {
 static const CopyToRoutine *
 CopyToGetRoutine(const CopyFormatOptions *opts)
 {
-	if (OidIsValid(opts->handler))
-	{
-		Datum		datum;
-		Node	   *routine;
-
-		datum = OidFunctionCall1(opts->handler, BoolGetDatum(false));
-		routine = (Node *) DatumGetPointer(datum);
-		if (routine == NULL || !IsA(routine, CopyToRoutine))
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("COPY handler function %s.%s did not return CopyToRoutine struct",
-							get_namespace_name(get_func_namespace(opts->handler)),
-							get_func_name(opts->handler))));
-		return castNode(CopyToRoutine, routine);
-	}
-	else if (opts->csv_mode)
-		return &CopyToRoutineCSV;
-	else if (opts->binary)
-		return &CopyToRoutineBinary;
+	Oid			handler = opts->handler;
+	Datum		datum;
+	Node	   *routine;
 
 	/* default is text */
-	return &CopyToRoutineText;
+	if (!OidIsValid(handler))
+		handler = F_TEXT_INTERNAL;
+
+	datum = OidFunctionCall1(handler, BoolGetDatum(false));
+	routine = (Node *) DatumGetPointer(datum);
+	if (routine == NULL || !IsA(routine, CopyToRoutine))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("COPY handler function %s.%s did not return CopyToRoutine struct",
+						get_namespace_name(get_func_namespace(handler)),
+						get_func_name(handler))));
+	return castNode(CopyToRoutine, routine);
 }
 
 /* Implementation of the start callback for text and CSV formats */
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index ba46bfa48a8..e038157eb74 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -12572,4 +12572,15 @@
   proargnames => '{pid,io_id,io_generation,state,operation,off,length,target,handle_data_len,raw_result,result,target_desc,f_sync,f_localmem,f_buffered}',
   prosrc => 'pg_get_aios' },
 
+# COPY handlers
+{ oid => '8100', descr => 'text COPY FORMAT handler',
+  proname => 'text', provolatile => 'i', prorettype => 'copy_handler',
+  proargtypes => 'internal', prosrc => 'copy_text_handler' },
+{ oid => '8101', descr => 'csv COPY FORMAT handler',
+  proname => 'csv', provolatile => 'i', prorettype => 'copy_handler',
+  proargtypes => 'internal', prosrc => 'copy_csv_handler' },
+{ oid => '8102', descr => 'binary COPY FORMAT handler',
+  proname => 'binary', provolatile => 'i', prorettype => 'copy_handler',
+  proargtypes => 'internal', prosrc => 'copy_binary_handler' },
+
 ]
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index 6df1f8a3b9b..4525261fcc4 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -87,7 +87,7 @@ typedef struct CopyFormatOptions
 	CopyLogVerbosityChoice log_verbosity;	/* verbosity of logged messages */
 	int64		reject_limit;	/* maximum tolerable number of errors */
 	List	   *convert_select; /* list of column names (can be NIL) */
-	Oid			handler;		/* handler function for custom format routine */
+	Oid			handler;		/* handler function */
 } CopyFormatOptions;
 
 /* These are private in commands/copy[from|to]_internal.h */
diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h
index f9e27152313..51d181c3ab4 100644
--- a/src/include/commands/copyfrom_internal.h
+++ b/src/include/commands/copyfrom_internal.h
@@ -14,7 +14,7 @@
 #ifndef COPYFROM_INTERNAL_H
 #define COPYFROM_INTERNAL_H
 
-#include "commands/copy.h"
+#include "commands/copyapi.h"
 #include "commands/trigger.h"
 #include "nodes/miscnodes.h"
 
@@ -197,4 +197,8 @@ extern bool CopyFromCSVOneRow(CopyFromState cstate, ExprContext *econtext,
 extern bool CopyFromBinaryOneRow(CopyFromState cstate, ExprContext *econtext,
 								 Datum *values, bool *nulls);
 
+extern PGDLLIMPORT const CopyFromRoutine CopyFromRoutineText;
+extern PGDLLIMPORT const CopyFromRoutine CopyFromRoutineCSV;
+extern PGDLLIMPORT const CopyFromRoutine CopyFromRoutineBinary;
+
 #endif							/* COPYFROM_INTERNAL_H */
diff --git a/src/include/commands/copyto_internal.h b/src/include/commands/copyto_internal.h
index 3bd9d702bf0..9faf97c718a 100644
--- a/src/include/commands/copyto_internal.h
+++ b/src/include/commands/copyto_internal.h
@@ -14,7 +14,7 @@
 #ifndef COPYTO_INTERNAL_H
 #define COPYTO_INTERNAL_H
 
-#include "commands/copy.h"
+#include "commands/copyapi.h"
 #include "executor/execdesc.h"
 #include "executor/tuptable.h"
 #include "nodes/execnodes.h"
@@ -83,4 +83,8 @@ typedef struct CopyToStateData
 	void	   *opaque;			/* private space */
 } CopyToStateData;
 
+extern PGDLLIMPORT const CopyToRoutine CopyToRoutineText;
+extern PGDLLIMPORT const CopyToRoutine CopyToRoutineCSV;
+extern PGDLLIMPORT const CopyToRoutine CopyToRoutineBinary;
+
 #endif							/* COPYTO_INTERNAL_H */
diff --git a/src/test/modules/test_copy_format/expected/test_copy_format.out b/src/test/modules/test_copy_format/expected/test_copy_format.out
index 47a875f0ab1..aa51e480b1d 100644
--- a/src/test/modules/test_copy_format/expected/test_copy_format.out
+++ b/src/test/modules/test_copy_format/expected/test_copy_format.out
@@ -72,6 +72,41 @@ NOTICE:  CopyToEnd
 -- Reset data.
 TRUNCATE copy_data;
 INSERT INTO copy_data VALUES (1, 2, 3), (12, 34, 56), (123, 456, 789);
+-- test_copy_format extension installs text, csv and binary custom
+-- COPY handlers to the public schema but they must not be
+-- used. Builtin COPY handlers must be used.
+-- public.text must not be used
+COPY copy_data FROM stdin WITH (FORMAT text);
+COPY copy_data TO stdout WITH (FORMAT text);
+1	2	3
+12	34	56
+123	456	789
+COPY copy_data FROM stdin WITH (FORMAT 'pg_catalog.text');
+COPY copy_data TO stdout WITH (FORMAT 'pg_catalog.text');
+1	2	3
+12	34	56
+123	456	789
+-- public.csv must not be used
+COPY copy_data FROM stdin WITH (FORMAT csv);
+COPY copy_data TO stdout WITH (FORMAT csv);
+1,2,3
+12,34,56
+123,456,789
+COPY copy_data FROM stdin WITH (FORMAT 'pg_catalog.csv');
+COPY copy_data TO stdout WITH (FORMAT 'pg_catalog.csv');
+1,2,3
+12,34,56
+123,456,789
+-- public.binary must not be used
+\getenv abs_builddir PG_ABS_BUILDDIR
+\set filename :abs_builddir '/results/binary.data'
+COPY copy_data TO :'filename' WITH (FORMAT binary);
+COPY copy_data FROM :'filename' WITH (FORMAT binary);
+COPY copy_data TO :'filename' WITH (FORMAT 'pg_catalog.binary');
+COPY copy_data FROM :'filename' WITH (FORMAT 'pg_catalog.binary');
+-- Reset data.
+TRUNCATE copy_data;
+INSERT INTO copy_data VALUES (1, 2, 3), (12, 34, 56), (123, 456, 789);
 DROP EXTENSION test_copy_format;
 -- Install custom COPY handlers to a schema that isn't included in
 -- search_path.
diff --git a/src/test/modules/test_copy_format/sql/test_copy_format.sql b/src/test/modules/test_copy_format/sql/test_copy_format.sql
index c7beb2fb8ae..3b7f6e72e13 100644
--- a/src/test/modules/test_copy_format/sql/test_copy_format.sql
+++ b/src/test/modules/test_copy_format/sql/test_copy_format.sql
@@ -43,6 +43,38 @@ COPY copy_data TO stdout WITH (FORMAT 'test_copy_format');
 TRUNCATE copy_data;
 INSERT INTO copy_data VALUES (1, 2, 3), (12, 34, 56), (123, 456, 789);
 
+-- test_copy_format extension installs text, csv and binary custom
+-- COPY handlers to the public schema but they must not be
+-- used. Builtin COPY handlers must be used.
+
+-- public.text must not be used
+COPY copy_data FROM stdin WITH (FORMAT text);
+\.
+COPY copy_data TO stdout WITH (FORMAT text);
+COPY copy_data FROM stdin WITH (FORMAT 'pg_catalog.text');
+\.
+COPY copy_data TO stdout WITH (FORMAT 'pg_catalog.text');
+
+-- public.csv must not be used
+COPY copy_data FROM stdin WITH (FORMAT csv);
+\.
+COPY copy_data TO stdout WITH (FORMAT csv);
+COPY copy_data FROM stdin WITH (FORMAT 'pg_catalog.csv');
+\.
+COPY copy_data TO stdout WITH (FORMAT 'pg_catalog.csv');
+
+-- public.binary must not be used
+\getenv abs_builddir PG_ABS_BUILDDIR
+\set filename :abs_builddir '/results/binary.data'
+COPY copy_data TO :'filename' WITH (FORMAT binary);
+COPY copy_data FROM :'filename' WITH (FORMAT binary);
+COPY copy_data TO :'filename' WITH (FORMAT 'pg_catalog.binary');
+COPY copy_data FROM :'filename' WITH (FORMAT 'pg_catalog.binary');
+
+-- Reset data.
+TRUNCATE copy_data;
+INSERT INTO copy_data VALUES (1, 2, 3), (12, 34, 56), (123, 456, 789);
+
 DROP EXTENSION test_copy_format;

diff --git a/src/test/modules/test_copy_format/test_copy_format--1.0.sql b/src/test/modules/test_copy_format/test_copy_format--1.0.sql
index c1a137181f8..bfa1900e828 100644
--- a/src/test/modules/test_copy_format/test_copy_format--1.0.sql
+++ b/src/test/modules/test_copy_format/test_copy_format--1.0.sql
@@ -22,3 +22,18 @@ CREATE FUNCTION test_copy_format_wrong_return_value(internal)
 	RETURNS copy_handler
 	AS 'MODULE_PATHNAME', 'test_copy_format_wrong_return_value'
 	LANGUAGE C;
+
+CREATE FUNCTION text(internal)
+	RETURNS copy_handler
+	AS 'MODULE_PATHNAME', 'test_copy_format'
+	LANGUAGE C;
+
+CREATE FUNCTION csv(internal)
+	RETURNS copy_handler
+	AS 'MODULE_PATHNAME', 'test_copy_format'
+	LANGUAGE C;
+
+CREATE FUNCTION binary(internal)
+	RETURNS copy_handler
+	AS 'MODULE_PATHNAME', 'test_copy_format'
+	LANGUAGE C;
-- 
2.47.2

>From 6e014bf226713a2c9f37da4c4f337128c4392212 Mon Sep 17 00:00:00 2001
From: Sutou Kouhei <[email-masked]>
Date: Fri, 25 Apr 2025 18:49:41 +0900
Subject: [PATCH v40 5/6] Remove CopyFormatOptions::{binary,csv_mode}

Because we can compute them from CopyFormatOptions::handler.
---
 src/backend/commands/copy.c          | 61 +++++++++++++---------------
 src/backend/commands/copyfrom.c      |  2 +-
 src/backend/commands/copyfromparse.c |  7 ++--
 src/backend/commands/copyto.c        |  4 +-
 src/include/commands/copy.h          |  2 -
 5 files changed, 36 insertions(+), 40 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 38ed8bccacd..21db5e964cf 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -38,6 +38,7 @@
 #include "parser/parse_relation.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/regproc.h"
 #include "utils/rel.h"
@@ -508,6 +509,8 @@ ProcessCopyOptions(ParseState *pstate,
 	bool		on_error_specified = false;
 	bool		log_verbosity_specified = false;
 	bool		reject_limit_specified = false;
+	bool		binary = false;
+	bool		csv_mode = false;
 	ListCell   *option;
 
 	/* Support external use for option sanity checking */
@@ -525,8 +528,6 @@ ProcessCopyOptions(ParseState *pstate,
 		{
 			char	   *format = defGetString(defel);
 			List	   *qualified_format;
-			char	   *schema;
-			char	   *fmt;
 			Oid			arg_types[1];
 			Oid			handler = InvalidOid;
 
@@ -535,15 +536,6 @@ ProcessCopyOptions(ParseState *pstate,
 			format_specified = true;
 
 			qualified_format = stringToQualifiedNameList(format, NULL);
-			DeconstructQualifiedName(qualified_format, &schema, &fmt);
-			if (!schema || strcmp(schema, "pg_catalog") == 0)
-			{
-				if (strcmp(fmt, "csv") == 0)
-					opts_out->csv_mode = true;
-				else if (strcmp(fmt, "binary") == 0)
-					opts_out->binary = true;
-			}
-
 			arg_types[0] = INTERNALOID;
 			handler = LookupFuncName(qualified_format, 1,
 									 arg_types, true);
@@ -562,6 +554,11 @@ ProcessCopyOptions(ParseState *pstate,
 						 parser_errposition(pstate, defel->location)));
 
 			opts_out->handler = handler;
+			if (opts_out->handler == F_CSV)
+				csv_mode = true;
+			else if (opts_out->handler == F_BINARY)
+				binary = true;
+
 		}
 		else if (strcmp(defel->defname, "freeze") == 0)
 		{
@@ -716,31 +713,31 @@ ProcessCopyOptions(ParseState *pstate,
 	 * Check for incompatible options (must do these three before inserting
 	 * defaults)
 	 */
-	if (opts_out->binary && opts_out->delim)
+	if (binary && opts_out->delim)
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
 				 errmsg("cannot specify %s in BINARY mode", "DELIMITER")));
 
-	if (opts_out->binary && opts_out->null_print)
+	if (binary && opts_out->null_print)
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("cannot specify %s in BINARY mode", "NULL")));
 
-	if (opts_out->binary && opts_out->default_print)
+	if (binary && opts_out->default_print)
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("cannot specify %s in BINARY mode", "DEFAULT")));
 
 	/* Set defaults for omitted options */
 	if (!opts_out->delim)
-		opts_out->delim = opts_out->csv_mode ? "," : "\t";
+		opts_out->delim = csv_mode ? "," : "\t";
 
 	if (!opts_out->null_print)
-		opts_out->null_print = opts_out->csv_mode ? "" : "\\N";
+		opts_out->null_print = csv_mode ? "" : "\\N";
 	opts_out->null_print_len = strlen(opts_out->null_print);
 
-	if (opts_out->csv_mode)
+	if (csv_mode)
 	{
 		if (!opts_out->quote)
 			opts_out->quote = "\"";
@@ -788,7 +785,7 @@ ProcessCopyOptions(ParseState *pstate,
 	 * future-proofing.  Likewise we disallow all digits though only octal
 	 * digits are actually dangerous.
 	 */
-	if (!opts_out->csv_mode &&
+	if (!csv_mode &&
 		strchr("\\.abcdefghijklmnopqrstuvwxyz0123456789",
 			   opts_out->delim[0]) != NULL)
 		ereport(ERROR,
@@ -796,43 +793,43 @@ ProcessCopyOptions(ParseState *pstate,
 				 errmsg("COPY delimiter cannot be \"%s\"", opts_out->delim)));
 
 	/* Check header */
-	if (opts_out->binary && opts_out->header_line)
+	if (binary && opts_out->header_line)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
 				 errmsg("cannot specify %s in BINARY mode", "HEADER")));
 
 	/* Check quote */
-	if (!opts_out->csv_mode && opts_out->quote != NULL)
+	if (!csv_mode && opts_out->quote != NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
 				 errmsg("COPY %s requires CSV mode", "QUOTE")));
 
-	if (opts_out->csv_mode && strlen(opts_out->quote) != 1)
+	if (csv_mode && strlen(opts_out->quote) != 1)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("COPY quote must be a single one-byte character")));
 
-	if (opts_out->csv_mode && opts_out->delim[0] == opts_out->quote[0])
+	if (csv_mode && opts_out->delim[0] == opts_out->quote[0])
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("COPY delimiter and quote must be different")));
 
 	/* Check escape */
-	if (!opts_out->csv_mode && opts_out->escape != NULL)
+	if (!csv_mode && opts_out->escape != NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
 				 errmsg("COPY %s requires CSV mode", "ESCAPE")));
 
-	if (opts_out->csv_mode && strlen(opts_out->escape) != 1)
+	if (csv_mode && strlen(opts_out->escape) != 1)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("COPY escape must be a single one-byte character")));
 
 	/* Check force_quote */
-	if (!opts_out->csv_mode && (opts_out->force_quote || opts_out->force_quote_all))
+	if (!csv_mode && (opts_out->force_quote || opts_out->force_quote_all))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -846,8 +843,8 @@ ProcessCopyOptions(ParseState *pstate,
 						"COPY FROM")));
 
 	/* Check force_notnull */
-	if (!opts_out->csv_mode && (opts_out->force_notnull != NIL ||
-								opts_out->force_notnull_all))
+	if (!csv_mode && (opts_out->force_notnull != NIL ||
+					  opts_out->force_notnull_all))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -862,8 +859,8 @@ ProcessCopyOptions(ParseState *pstate,
 						"COPY TO")));
 
 	/* Check force_null */
-	if (!opts_out->csv_mode && (opts_out->force_null != NIL ||
-								opts_out->force_null_all))
+	if (!csv_mode && (opts_out->force_null != NIL ||
+					  opts_out->force_null_all))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -887,7 +884,7 @@ ProcessCopyOptions(ParseState *pstate,
 						"NULL")));
 
 	/* Don't allow the CSV quote char to appear in the null string. */
-	if (opts_out->csv_mode &&
+	if (csv_mode &&
 		strchr(opts_out->null_print, opts_out->quote[0]) != NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -923,7 +920,7 @@ ProcessCopyOptions(ParseState *pstate,
 							"DEFAULT")));
 
 		/* Don't allow the CSV quote char to appear in the default string. */
-		if (opts_out->csv_mode &&
+		if (csv_mode &&
 			strchr(opts_out->default_print, opts_out->quote[0]) != NULL)
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -940,7 +937,7 @@ ProcessCopyOptions(ParseState *pstate,
 					 errmsg("NULL specification and DEFAULT specification cannot be the same")));
 	}
 	/* Check on_error */
-	if (opts_out->binary && opts_out->on_error != COPY_ON_ERROR_STOP)
+	if (binary && opts_out->on_error != COPY_ON_ERROR_STOP)
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("only ON_ERROR STOP is allowed in BINARY mode")));
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index 74a8051c24c..b09b6b3e101 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -275,7 +275,7 @@ CopyFromErrorCallback(void *arg)
 				   cstate->cur_relname);
 		return;
 	}
-	if (cstate->opts.binary)
+	if (cstate->opts.handler == F_BINARY)
 	{
 		/* can't usefully display the data */
 		if (cstate->cur_attname)
diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index de68b53b000..148fa1f2062 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -73,6 +73,7 @@
 #include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "utils/builtins.h"
+#include "utils/fmgroids.h"
 #include "utils/rel.h"
 
 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
@@ -171,7 +172,7 @@ ReceiveCopyBegin(CopyFromState cstate)
 {
 	StringInfoData buf;
 	int			natts = list_length(cstate->attnumlist);
-	int16		format = (cstate->opts.binary ? 1 : 0);
+	int16		format = (cstate->opts.handler == F_BINARY ? 1 : 0);
 	int			i;
 
 	pq_beginmessage(&buf, PqMsg_CopyInResponse);
@@ -758,7 +759,7 @@ bool
 NextCopyFromRawFields(CopyFromState cstate, char ***fields, int *nfields)
 {
 	return NextCopyFromRawFieldsInternal(cstate, fields, nfields,
-										 cstate->opts.csv_mode);
+										 cstate->opts.handler == F_CSV);
 }
 
 /*
@@ -785,7 +786,7 @@ NextCopyFromRawFieldsInternal(CopyFromState cstate, char ***fields, int *nfields
 	bool		done;
 
 	/* only available for text or csv input */
-	Assert(!cstate->opts.binary);
+	Assert(cstate->opts.handler != F_BINARY);
 
 	/* on input check that the header line is correct if needed */
 	if (cstate->cur_lineno == 0 && cstate->opts.header_line)
diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index 4e1b154cad2..4f8f5813172 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -167,7 +167,7 @@ CopyToTextLikeStart(CopyToState cstate, TupleDesc tupDesc)
 
 			colname = NameStr(TupleDescAttr(tupDesc, attnum - 1)->attname);
 
-			if (cstate->opts.csv_mode)
+			if (cstate->opts.handler == F_CSV)
 				CopyAttributeOutCSV(cstate, colname, false);
 			else
 				CopyAttributeOutText(cstate, colname);
@@ -344,7 +344,7 @@ SendCopyBegin(CopyToState cstate)
 {
 	StringInfoData buf;
 	int			natts = list_length(cstate->attnumlist);
-	int16		format = (cstate->opts.binary ? 1 : 0);
+	int16		format = (cstate->opts.handler == F_BINARY ? 1 : 0);
 	int			i;
 
 	pq_beginmessage(&buf, PqMsg_CopyOutResponse);
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index 4525261fcc4..04f8f5ef1b2 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -61,9 +61,7 @@ typedef struct CopyFormatOptions
 	/* parameters from the COPY command */
 	int			file_encoding;	/* file or remote side's character encoding,
 								 * -1 if not specified */
-	bool		binary;			/* binary format? */
 	bool		freeze;			/* freeze rows on loading? */
-	bool		csv_mode;		/* Comma Separated Value format? */
 	CopyHeaderChoice header_line;	/* header line? */
 	char	   *null_print;		/* NULL marker string (server encoding!) */
 	int			null_print_len; /* length of same */
-- 
2.47.2

>From 421c34b76a5e9fe45b49bdbe52ecda4d0f638617 Mon Sep 17 00:00:00 2001
From: Sutou Kouhei <[email-masked]>
Date: Wed, 19 Mar 2025 11:46:34 +0900
Subject: [PATCH v40 6/6] Add document how to write a COPY handler

This is WIP because we haven't decided our API yet.

Co-authored-by: David G. Johnston <[email-masked]>
---
 doc/src/sgml/copy-handler.sgml | 394 +++++++++++++++++++++++++++++++++
 doc/src/sgml/filelist.sgml     |   1 +
 doc/src/sgml/postgres.sgml     |   1 +
 src/include/commands/copyapi.h |   9 +-
 4 files changed, 401 insertions(+), 4 deletions(-)
 create mode 100644 doc/src/sgml/copy-handler.sgml

diff --git a/doc/src/sgml/copy-handler.sgml b/doc/src/sgml/copy-handler.sgml
new file mode 100644
index 00000000000..5bc87d16662
--- /dev/null
+++ b/doc/src/sgml/copy-handler.sgml
@@ -0,0 +1,394 @@
+<!-- doc/src/sgml/copy-handler.sgml -->
+
+<chapter id="copy-handler">
+ <title>Writing a Copy Handler</title>
+
+ <indexterm zone="copy-handler">
+  <primary><literal>COPY</literal> handler</primary>
+ </indexterm>
+
+ <para>
+  <productname>PostgreSQL</productname> supports
+  custom <link linkend="sql-copy"><literal>COPY</literal></link> handlers;
+  adding additional <replaceable>format_name</replaceable> options to
+  the <literal>FORMAT</literal> clause.
+ </para>
+
+ <para>
+  At the SQL level, a copy handler method is represented by a single SQL
+  function (see <xref linkend="sql-createfunction"/>), typically implemented in
+  C, having the signature
+<synopsis>
+<replaceable>format_name</replaceable>(internal) RETURNS <literal>copy_handler</literal>
+</synopsis>
+  The function's name is then accepted as a
+  valid <replaceable>format_name</replaceable>. The return
+  pseudo-type <literal>copy_handler</literal> informs the system that this
+  function needs to be registered as a copy handler.
+  The <type>internal</type> argument is a dummy that prevents this function
+  from being called directly from an SQL command. As the handler
+  implementation must be server-lifetime immutable; this SQL function's
+  volatility should be marked immutable. The <literal>link_symbol</literal>
+  for this function is the name of the implementation function, described
+  next.
+ </para>
+
+ <para>
+  The implementation function signature expected for the function named
+  in the <literal>link_symbol</literal> is:
+<synopsis>
+Datum
+<replaceable>copy_format_handler</replaceable>(PG_FUNCTION_ARGS)
+</synopsis>
+  The convention for the name is to replace the word
+  <replaceable>format</replaceable> in the placeholder above with the value given
+  to <replaceable>format_name</replaceable> in the SQL function.
+  The first argument is a <type>boolean</type> that indicates whether the handler
+  must provide a pointer to its implementation for <literal>COPY FROM</literal>
+  (a <type>CopyFromRoutine *</type>). If <literal>false</literal>, the handler
+  must provide a pointer to its implementation of <literal>COPY TO</literal>
+  (a <type>CopyToRoutine *</type>). These structs are declared in
+  <filename>src/include/commands/copyapi.h</filename>.
+ </para>
+
+ <para>
+  The structs hold pointers to implementation functions for initializing,
+  starting, processing rows, and ending a copy operation. The specific
+  structures vary a bit between <literal>COPY FROM</literal> and
+  <literal>COPY TO</literal> so the next two sections describes each
+  in detail.
+ </para>
+
+ <sect1 id="copy-handler-from">
+  <title>Copy From Handler</title>
+
+  <para>
+   The opening to this chapter describes how the executor will call the main
+   handler function with, in this case,
+   a <type>boolean</type> <literal>true</literal>, and expect to receive a
+   <type>CopyFromRoutine *</type> <type>Datum</type>. This section describes
+   the components of the <type>CopyFromRoutine</type> struct.
+  </para>
+
+  <para>
+<programlisting>
+void
+CopyFromInFunc(CopyFromState cstate,
+               Oid atttypid,
+               FmgrInfo *finfo,
+               Oid *typioparam);
+</programlisting>
+
+   This sets input function information for the
+   given <literal>atttypid</literal> attribute. This function is called once
+   at the beginning of <literal>COPY FROM</literal>. If
+   this <literal>COPY</literal> handler doesn't use any input functions, this
+   function doesn't need to do anything.
+
+   <variablelist>
+    <varlistentry>
+     <term><literal>CopyFromState *cstate</literal></term>
+     <listitem>
+      <para>
+       This is an internal struct that contains all the state variables used
+       throughout a <literal>COPY FROM</literal> operation.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>Oid atttypid</literal></term>
+     <listitem>
+      <para>
+       This is the OID of data type used by the relation's attribute.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>FmgrInfo *finfo</literal></term>
+     <listitem>
+      <para>
+       This can be optionally filled to provide the catalog information of
+       the input function.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>Oid *typioparam</literal></term>
+     <listitem>
+      <para>
+       This can be optionally filled to define the OID of the type to
+       pass to the input function.
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+  </para>
+
+  <para>
+<programlisting>
+void
+CopyFromStart(CopyFromState cstate,
+              TupleDesc tupDesc);
+</programlisting>
+
+   This starts a <literal>COPY FROM</literal>. This function is called once at
+   the beginning of <literal>COPY FROM</literal>.
+
+   <variablelist>
+    <varlistentry>
+     <term><literal>CopyFromState *cstate</literal></term>
+     <listitem>
+      <para>
+       This is an internal struct that contains all the state variables used
+       throughout a <literal>COPY FROM</literal> operation.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>TupleDesc tupDesc</literal></term>
+     <listitem>
+      <para>
+       This is the tuple descriptor of the relation where the data needs to be
+       copied. This can be used for any initialization steps required by a
+       format.
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+  </para>
+
+  <para>
+<programlisting>
+bool
+CopyFromOneRow(CopyFromState cstate,
+               ExprContext *econtext,
+               Datum *values,
+               bool *nulls);
+</programlisting>
+
+   This reads one row from the source and fill <literal>values</literal>
+   and <literal>nulls</literal>. If there is one or more tuples to be read,
+   this must return <literal>true</literal>. If there are no more tuples to
+   read, this must return <literal>false</literal>.
+
+   <variablelist>
+    <varlistentry>
+     <term><literal>CopyFromState *cstate</literal></term>
+     <listitem>
+      <para>
+       This is an internal struct that contains all the state variables used
+       throughout a <literal>COPY FROM</literal> operation.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>ExprContext *econtext</literal></term>
+     <listitem>
+      <para>
+       This is used to evaluate default expression for each column that is
+       either not read from the file or is using
+       the <literal>DEFAULT</literal> option of <literal>COPY
+       FROM</literal>. It is <literal>NULL</literal> if no default values are
+       used.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>Datum *values</literal></term>
+     <listitem>
+      <para>
+       This is an output variable to store read tuples.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>bool *nulls</literal></term>
+     <listitem>
+      <para>
+       This is an output variable to store whether the read columns
+       are <literal>NULL</literal> or not.
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+  </para>
+
+  <para>
+<programlisting>
+void
+CopyFromEnd(CopyFromState cstate);
+</programlisting>
+
+   This ends a <literal>COPY FROM</literal>. This function is called once at
+   the end of <literal>COPY FROM</literal>.
+
+   <variablelist>
+    <varlistentry>
+     <term><literal>CopyFromState *cstate</literal></term>
+     <listitem>
+      <para>
+       This is an internal struct that contains all the state variables used
+       throughout a <literal>COPY FROM</literal> operation.
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+  </para>
+
+  <para>
+   TODO: Add CopyFromStateGetData() and CopyFromSkipErrowRow()?
+  </para>
+ </sect1>
+
+ <sect1 id="copy-handler-to">
+  <title>Copy To Handler</title>
+
+  <para>
+   The <literal>COPY</literal> handler function for <literal>COPY
+   TO</literal> returns a <type>CopyToRoutine</type> struct containing
+   pointers to the functions described below. All functions are required.
+  </para>
+
+  <para>
+<programlisting>
+void
+CopyToOutFunc(CopyToState cstate,
+              Oid atttypid,
+              FmgrInfo *finfo);
+</programlisting>
+
+   This sets output function information for the
+   given <literal>atttypid</literal> attribute. This function is called once
+   at the beginning of <literal>COPY TO</literal>. If
+   this <literal>COPY</literal> handler doesn't use any output functions, this
+   function doesn't need to do anything.
+
+   <variablelist>
+    <varlistentry>
+     <term><literal>CopyToState *cstate</literal></term>
+     <listitem>
+      <para>
+       This is an internal struct that contains all the state variables used
+       throughout a <literal>COPY TO</literal> operation.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>Oid atttypid</literal></term>
+     <listitem>
+      <para>
+       This is the OID of data type used by the relation's attribute.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>FmgrInfo *finfo</literal></term>
+     <listitem>
+      <para>
+       This can be optionally filled to provide the catalog information of
+       the output function.
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+  </para>
+
+  <para>
+<programlisting>
+void
+CopyToStart(CopyToState cstate,
+            TupleDesc tupDesc);
+</programlisting>
+
+   This starts a <literal>COPY TO</literal>. This function is called once at
+   the beginning of <literal>COPY TO</literal>.
+
+   <variablelist>
+    <varlistentry>
+     <term><literal>CopyToState *cstate</literal></term>
+     <listitem>
+      <para>
+       This is an internal struct that contains all the state variables used
+       throughout a <literal>COPY TO</literal> operation.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>TupleDesc tupDesc</literal></term>
+     <listitem>
+      <para>
+       This is the tuple descriptor of the relation where the data is read.
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+  </para>
+
+  <para>
+<programlisting>
+bool
+CopyToOneRow(CopyToState cstate,
+             TupleTableSlot *slot);
+</programlisting>
+
+   This writes one row stored in <literal>slot</literal> to the destination.
+
+   <variablelist>
+    <varlistentry>
+     <term><literal>CopyToState *cstate</literal></term>
+     <listitem>
+      <para>
+       This is an internal struct that contains all the state variables used
+       throughout a <literal>COPY TO</literal> operation.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>TupleTableSlot *slot</literal></term>
+     <listitem>
+      <para>
+       This is used to get row to be written.
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+  </para>
+
+  <para>
+<programlisting>
+void
+CopyToEnd(CopyToState cstate);
+</programlisting>
+
+   This ends a <literal>COPY TO</literal>. This function is called once at
+   the end of <literal>COPY TO</literal>.
+
+   <variablelist>
+    <varlistentry>
+     <term><literal>CopyToState *cstate</literal></term>
+     <listitem>
+      <para>
+       This is an internal struct that contains all the state variables used
+       throughout a <literal>COPY TO</literal> operation.
+      </para>
+     </listitem>
+    </varlistentry>
+   </variablelist>
+  </para>
+
+  <para>
+   TODO: Add CopyToStateFlush()?
+  </para>
+ </sect1>
+</chapter>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index fef9584f908..700cf22b502 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -107,6 +107,7 @@
 <!ENTITY storage    SYSTEM "storage.sgml">
 <!ENTITY transaction     SYSTEM "xact.sgml">
 <!ENTITY tablesample-method SYSTEM "tablesample-method.sgml">
+<!ENTITY copy-handler SYSTEM "copy-handler.sgml">
 <!ENTITY wal-for-extensions SYSTEM "wal-for-extensions.sgml">
 <!ENTITY generic-wal SYSTEM "generic-wal.sgml">
 <!ENTITY custom-rmgr SYSTEM "custom-rmgr.sgml">
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index af476c82fcc..8ba319ae2df 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -254,6 +254,7 @@ break is not needed in a wider output rendering.
   &plhandler;
   &fdwhandler;
   &tablesample-method;
+  &copy-handler;
   &custom-scan;
   &geqo;
   &tableam;
diff --git a/src/include/commands/copyapi.h b/src/include/commands/copyapi.h
index 500ece7d5bb..24710cb667a 100644
--- a/src/include/commands/copyapi.h
+++ b/src/include/commands/copyapi.h
@@ -28,10 +28,10 @@ typedef struct CopyToRoutine
 	 * Set output function information. This callback is called once at the
 	 * beginning of COPY TO.
 	 *
+	 * 'atttypid' is the OID of data type used by the relation's attribute.
+	 *
 	 * 'finfo' can be optionally filled to provide the catalog information of
 	 * the output function.
-	 *
-	 * 'atttypid' is the OID of data type used by the relation's attribute.
 	 */
 	void		(*CopyToOutFunc) (CopyToState cstate, Oid atttypid,
 								  FmgrInfo *finfo);
@@ -70,12 +70,13 @@ typedef struct CopyFromRoutine
 	 * Set input function information. This callback is called once at the
 	 * beginning of COPY FROM.
 	 *
+	 * 'atttypid' is the OID of data type used by the relation's attribute.
+	 *
 	 * 'finfo' can be optionally filled to provide the catalog information of
 	 * the input function.
 	 *
 	 * 'typioparam' can be optionally filled to define the OID of the type to
-	 * pass to the input function.'atttypid' is the OID of data type used by
-	 * the relation's attribute.
+	 * pass to the input function.
 	 */
 	void		(*CopyFromInFunc) (CopyFromState cstate, Oid atttypid,
 								   FmgrInfo *finfo, Oid *typioparam);
-- 
2.47.2

---

From: Masahiko Sawada <[email-masked]>
Date: Thu, 1 May 2025 12:15:30 -0700

> 1.: I didn't do anything. Because there is no suggestion.

Thank you for updating the patches.

One of the primary considerations we need to address is the treatment
of the specified format name. The current patch set utilizes built-in
formats (namely 'csv', 'text', and 'binary') when the format name is
either unqualified or explicitly specified with 'pg_catalog' as the
schema. In all other cases, we search for custom format handler
functions based on the search_path. To be frank, I have reservations
about this interface design, as the dependence of the specified custom
format name on the search_path could potentially confuse users.

In light of these concerns, I've been contemplating alternative
interface designs. One promising approach would involve registering
custom copy formats via a C function during module loading
(specifically, in _PG_init()). This method would require extension
authors to invoke a registration function, say
RegisterCustomCopyFormat(), in _PG_init() as follows:

JsonLinesFormatId = RegisterCustomCopyFormat("jsonlines",
                                             &JsonLinesCopyToRoutine,
                                             &JsonLinesCopyFromRoutine);

The registration function would validate the format name and store it
in TopMemoryContext. It would then return a unique identifier that can
be used subsequently to reference the custom copy format extension.

Custom copy format modules could be loaded through
shared_preload_libraries, session_preload_libraries, or the LOAD
command. Extensions could register their own options within this
framework, for example:

RegisterCustomCopyFormatOption(JsonLinesFormatId,
    "custom_option",
    custom_option_handler);

This approach offers several advantages: it would eliminate the
search_path issue, provide greater flexibility, and potentially
simplify the overall interface for users and developers alike. We
might be able to provide a view showing the registered custom COPY
format in the future. Also, these interfaces align with other
customizable functionalities such as custom rmgr, custom lwlock,
custom waitevent, and custom EXPLAIN option etc.

Feedback is very welcome.

Regards,

---

From: Michael Paquier <[email-masked]>
Date: Fri, 2 May 2025 08:03:50 +0900

> be used subsequently to reference the custom copy format extension.

Hmm.  How much should we care about the observability of the COPY
format used by a given backend?  Storing this information in a
backend's TopMemoryContext is OK to get the extensibility basics to
work, but could it make sense to use some shmem state to allocate a
uint32 ID that could be shared by all backends.  Contrary to EXPLAIN,
COPY commands usually run for a very long time, so I am wondering if 
these APIs should be designed so as it would be possible to monitor
the format used.  One layer where the format information could be made
available is the progress reporting view for COPY, for example.  I can
also imagine a pgstats kind where we do COPY stats aggregates, with a
per-format pgstats kind, and sharing a fixed ID across multiple
backends is relevant (when flushing the stats at shutdown, we would
use a name/ID mapping like replication slots).

I don't think that this needs to be relevant for the option part, just 
for the format where, I suspect, we should store in a shmem array
based on the ID allocated the name of the format, the library of the
callback and the function name fed to load_external_function().

Note that custom LWLock and wait events use a shmem state for
monitoring purposes, where we are able to do ID->format name lookups 
as much as format->ID lookups.  Perhaps it's OK not to do that for
COPY, but I am wondering if we'd better design things from scratch
with states in shmem state knowing that COPY is a long-running
operation, and that if one mixes multiple formats they would most
likely want to know which formats are bottlenecks, through SQL.  Cloud
providers would love that.

> custom waitevent, and custom EXPLAIN option etc.

Yeah, agreed with the search_path concerns.  We are getting better at
making areas of Postgres more pluggable lately, having a loading path
where we don't have any of these potential issues by design matters.
--
Michael

---

From: Masahiko Sawada <[email-masked]>
Date: Fri, 2 May 2025 15:52:49 -0700

> providers would love that.

Good point. It would make sense to have such information as a map on
shmem. It might be better to use dshash here since a custom copy
format module can be loaded at runtime. Or we can use dynahash with
large enough elements.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Sat, 03 May 2025 11:19:58 +0900 (JST)

Hi,

In <CAD21AoBuEqcz2_+dpA3WTiDUF=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Thu, 1 May 2025 12:15:30 -0700,

> format name on the search_path could potentially confuse users.

How about requiring schema for all custom formats?

Valid:

  COPY ... TO ... (FORMAT 'text');
  COPY ... TO ... (FORMAT 'my_schema.jsonlines');

Invalid:

  COPY ... TO ... (FORMAT 'jsonlines'); -- no schema
  COPY ... TO ... (FORMAT 'pg_catalog.text'); -- needless schema

If we require "schema" for all custom formats, we don't need
to depend on search_path.

> be used subsequently to reference the custom copy format extension.

I don't object the suggested interface because I don't have
a strong opinion how to implement this feature.

Why do we need to assign a unique ID? For performance? For
RegisterCustomCopyFormatOption()?

I think that we don't need to use it so much in COPY. We
don't need to use format name and assigned ID after we
retrieve a corresponding Copy{To,From}Routine. Because all
needed information are in Copy{To,From}Routine.

>          Extensions could register their own options within this
> framework, for example:
> 

Can we defer to discuss how to add support for custom
options while we focus on the first implementation? Earlier
patch sets with the current approach had custom options
support but it's removed in the first implementation.

(BTW, I think that it's not a good API because we want COPY
FROM only options and COPY TO only options something like
"compression level".)

> simplify the overall interface for users and developers alike.

What contributes to the "flexibility"? Developers can call
multiple Register* functions in _PG_Init(), right?

Thanks,
-- 
kou

---

From: Sutou Kouhei <[email-masked]>
Date: Sat, 03 May 2025 11:24:06 +0900 (JST)

Hi,

In <CAD21AoB82+MoP_RJ=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Fri, 2 May 2025 15:52:49 -0700,

> format module can be loaded at runtime. Or we can use dynahash with

If we don't need to assign an ID for each format, can we
avoid it? If we implement it, is this approach more complex
than the current table sampling method like approach?

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Fri, 2 May 2025 21:38:32 -0700

> to depend on search_path.

I'm concerned that users cannot use the same format name in the FORMAT
option depending on which schema the handler function is created.

> RegisterCustomCopyFormatOption()?

I think it's required for monitoring purposes for example. For
instance, we can set the format ID in the progress information and the
progress view can fetch the format name by the ID so that users can
see what format is being used in the COPY command.

> support but it's removed in the first implementation.

I think we can skip the custom option patch for the first
implementation but still need to discuss how we will be able to
implement it to understand the big picture of this feature. Otherwise
we could end up going the wrong direction.

> FROM only options and COPY TO only options something like

Why does this matter in terms of API? I think that even with this API
we can pass is_from to the option handler function so that it
validates the option based on it.

> multiple Register* functions in _PG_Init(), right?

I think that with a tablesample-like approach we need to do everything
based on one handler function and callbacks returned from it whereas
there is no such limitation with C API style.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Sat, 03 May 2025 13:56:39 +0900 (JST)

Hi,

In <CAD21AoBGRFStdVbHUcxL0QB8wn92J3Sn-6x=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Fri, 2 May 2025 21:38:32 -0700,

> option depending on which schema the handler function is created.

I'm not sure that it's a problem or not. If users want to
use the same format name, they can install the handler
function to the same schema.

> see what format is being used in the COPY command.

How about setting the format name instead of the format ID
in the progress information?

> we could end up going the wrong direction.

I think that we don't need to discuss it deeply because we
have many options with this approach. We can call C
functions in _PG_Init(). I think that this feature will not
be a blocker of this approach.

> validates the option based on it.

If we choose the API, each custom format developer needs to
handle the case in handler function. For example, if we pass
information whether this option is only for TO to
PostgreSQL, ProcessCopyOptions() not handler functions can
handle it.

Anyway, I think that we don't need to discuss this deeply
for now.

> there is no such limitation with C API style.

Thanks for clarifying it. It seems that my understanding is
correct.

I hope that the flexibility is needed flexibility and too
much flexibility doesn't introduce too much complexity.

Thanks,
-- 
kou

---

From: "David G. Johnston" <[email-masked]>
Date: Fri, 2 May 2025 22:36:06 -0700

> be used subsequently to reference the custom copy format extension.

How does this fix the search_path concern?  Are query writers supposed to
put JsonLinesFormatId into their queries?  Or are you just prohibiting a
DBA from ever installing an extension that wants to register a format name
that is already registered so that no namespace is ever required?

ISTM accommodating a namespace for formats is required just like we do for
virtually every other named object in the system.  At least, if we want to
play nice with extension authors.  It doesn’t have to be within the
existing pg_proc scope, we can create a new scope if desired, but
abolishing it seems unwise.

It would be more consistent with established policy if we didn’t make
exceptions for text/csv/binary - if the DBA permits a text format to exist
in a different schema and that schema appears first in the search_path,
unqualified references to text would resolve to the non-core handler.  We
already protect ourselves with safe search_paths.  This is really no
different than if someone wanted to implement a now() function and people
are putting pg_catalog from of existing usage.  It’s the DBAs problem, not
ours.

David J.

---

From: Masahiko Sawada <[email-masked]>
Date: Fri, 2 May 2025 22:57:53 -0700

On Fri, May 2, 2025 at 10:36 PM David G. Johnston
<[email-masked]> wrote:
> How does this fix the search_path concern?  Are query writers supposed to put JsonLinesFormatId into their queries?  Or are you just prohibiting a DBA from ever installing an extension that wants to register a format name that is already registered so that no namespace is ever required?

Users can specify "jsonlines", passed in the first argument to the
register function, to the COPY FORMAT option in this case.  While
JsonLinesFormatId is reserved for internal operations such as module
processing and monitoring, any attempt to load another custom COPY
format module named 'jsonlines' will result in an error.

> ISTM accommodating a namespace for formats is required just like we do for virtually every other named object in the system.  At least, if we want to play nice with extension authors.  It doesn’t have to be within the existing pg_proc scope, we can create a new scope if desired, but abolishing it seems unwise.
>
> It would be more consistent with established policy if we didn’t make exceptions for text/csv/binary - if the DBA permits a text format to exist in a different schema and that schema appears first in the search_path, unqualified references to text would resolve to the non-core handler.  We already protect ourselves with safe search_paths.  This is really no different than if someone wanted to implement a now() function and people are putting pg_catalog from of existing usage.  It’s the DBAs problem, not ours.

I'm concerned about allowing multiple 'text' format implementations
with identical names within the database, as this could lead to
considerable confusion. When users specify 'text', it would be more
logical to guarantee that the built-in 'text' format is consistently
used. This principle aligns with other customizable components, such
as custom resource managers, wait events, lightweight locks, and
custom scans. These components maintain their built-in data/types and
explicitly prevent the registration of duplicate names.

Regards,

---

From: Masahiko Sawada <[email-masked]>
Date: Fri, 2 May 2025 23:02:25 -0700

> in the progress information?

The progress view can know only numbers. We need to extend the
progress view infrastructure so that we can pass other data types.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Sat, 03 May 2025 15:20:46 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Fri, 2 May 2025 23:02:25 -0700,

> progress view infrastructure so that we can pass other data types.

Sorry. Could you tell me what APIs referred here?
pgstat_progress_*() functions in
src/include/utils/backend_progress.h?

Thanks,
-- 
kou

---

From: "David G. Johnston" <[email-masked]>
Date: Fri, 2 May 2025 23:37:36 -0700

On Friday, May 2, 2025, Masahiko Sawada <[email-masked]> wrote:

> used.

Do you want to only give text/csv/binary this special treatment or also any
future format name we ever decide to implement in core.  If an extension
takes up “xml” and we try to do that in core do we fail an upgrade because
of the conflict, and make it impossible to actually use said extension?

This principle aligns with other customizable components, such
> explicitly prevent the registration of duplicate names.

I am totally lost on how any of those resemble this feature.

I’m all for registration to enable additional options and features - but am
against moving away from turning format into a namespaced identifier.  This
is a query-facing feature where namespaces are common and fundamentally
required.  I have some sympathy for the fact that until now one could not
prefix text/binary/csv with pg_catalog to be fully safe, but in reality
DBAs/query authors either put pg_catalog first in their search_path or make
an informed decision when they deviate.  That is the established precedent
relevant to this feature.  The power, and responsibility for education,
lies with the user.

David J.

---

From: Masahiko Sawada <[email-masked]>
Date: Fri, 2 May 2025 23:37:46 -0700

> src/include/utils/backend_progress.h?

The progress information is stored in PgBackendStatus defined in
backend_status.h:

    /*
     * Command progress reporting.  Any command which wishes can advertise
     * that it is running by setting st_progress_command,
     * st_progress_command_target, and st_progress_param[].
     * st_progress_command_target should be the OID of the relation which the
     * command targets (we assume there's just one, as this is meant for
     * utility commands), but the meaning of each element in the
     * st_progress_param array is command-specific.
     */
    ProgressCommandType st_progress_command;
    Oid         st_progress_command_target;
    int64       st_progress_param[PGSTAT_NUM_PROGRESS_PARAM];

Then the progress view maps the numbers to the corresponding strings:

CREATE VIEW pg_stat_progress_copy AS
    SELECT
        S.pid AS pid, S.datid AS datid, D.datname AS datname,
        S.relid AS relid,
        CASE S.param5 WHEN 1 THEN 'COPY FROM'
                      WHEN 2 THEN 'COPY TO'
                      END AS command,
        CASE S.param6 WHEN 1 THEN 'FILE'
                      WHEN 2 THEN 'PROGRAM'
                      WHEN 3 THEN 'PIPE'
                      WHEN 4 THEN 'CALLBACK'
                      END AS "type",
        S.param1 AS bytes_processed,
        S.param2 AS bytes_total,
        S.param3 AS tuples_processed,
        S.param4 AS tuples_excluded,
        S.param7 AS tuples_skipped
    FROM pg_stat_get_progress_info('COPY') AS S
        LEFT JOIN pg_database D ON S.datid = D.oid;

So the idea is that the backend process sets the format ID somewhere
in st_progress_param, and then the progress view calls a SQL function,
say pg_stat_get_copy_format_name(), with the format ID that returns
the corresponding format name.

Regards,

---

From: Masahiko Sawada <[email-masked]>
Date: Sat, 3 May 2025 00:54:36 -0700

On Fri, May 2, 2025 at 11:37 PM David G. Johnston
<[email-masked]> wrote:
> Do you want to only give text/csv/binary this special treatment or also any future format name we ever decide to implement in core.  If an extension takes up “xml” and we try to do that in core do we fail an upgrade because of the conflict, and make it impossible to actually use said extension?

I guess that's an extension author's responsibility to upgrade its
extension so as to work with the new PostgreSQL version, or carefully
choose the format name. They can even name
'[extension_name].[format_name]' as a format name. Even with the
current patch design (i.e., search_path affects handler function
lookups), users would end up using the built-in 'xml' format without
notice after upgrade, no? I guess that could introduce another
problem.

I think that we need to ensure that if users specify text/csv/binary
the built-in formats are always used, to keep backward compatibility.

> I’m all for registration to enable additional options and features - but am against moving away from turning format into a namespaced identifier.  This is a query-facing feature where namespaces are common and fundamentally required.

That's a fair concern. But isn't the format name ultimately just an
option value, but not like a database object? As I mentioned above, I
think we need to keep backward compatibility but treating the built-in
formats special seems inconsistent with common name resolution
behavior.

Regards,

---

From: "David G. Johnston" <[email-masked]>
Date: Sat, 3 May 2025 07:42:08 -0700

> the built-in formats are always used, to keep backward compatibility.

That was my original thinking, but it’s inconsistent with how functions
behave today.  We don’t promise that installing extensions won’t cause
existing code to change.

>
>
> > I’m all for registration to enable additional options and features - but
> am against moving away from turning format into a namespaced identifier.
> This is a query-facing feature where namespaces are common and
> fundamentally required.
>
> option value, but not like a database object?

We get to decide that.  And deciding in favor of “extensible database
object in a namespace’ makes more sense - leveraging all that pre-existing
design to play more nicely with extensions and give DBAs control.  The SQL
command to add one is “create function” instead of “create copy format”.

David J.

---

From: Masahiko Sawada <[email-masked]>
Date: Sat, 3 May 2025 22:02:51 -0700

On Sat, May 3, 2025 at 7:42 AM David G. Johnston
<[email-masked]> wrote:
> That was my original thinking, but it’s inconsistent with how functions behave today.  We don’t promise that installing extensions won’t cause existing code to change.

I'm skeptical about whether that's an acceptable backward
compatibility breakage.

> We get to decide that.  And deciding in favor of “extensible database object in a namespace’ makes more sense - leveraging all that pre-existing design to play more nicely with extensions and give DBAs control.  The SQL command to add one is “create function” instead of “create copy format”.

I still don't fully understand why the FORMAT value alone needs to be
treated like a schema-qualified object. If the concern is about name
conflict with future built-in formats, I would argue that the same
concern applies to custom EXPLAIN options and logical decoding
plugins. To me, the benefit of treating the COPY FORMAT value as a
schema-qualified object seems limited. Meanwhile, the risk of not
protecting built-in formats like 'text', 'csv', and 'binary' is
significant. If those names can be shadowed by extension via
search_patch, we lose backward compatibility.

Regards,

---

From: "David G. Johnston" <[email-masked]>
Date: Sat, 3 May 2025 22:27:36 -0700

> I'm skeptical about whether that's an acceptable backward

I’m skeptical you are correctly defining what backward-compatibility
requires.

Well, the only potential breakage is that we are searching for a matching
function by signature without first limiting the mandated return type.  But
that is solve-able should anyone else see the problem as well.

The global format name has its merits but neither it nor the namespaced
format option suffer from breaking compatibility or policy.

> plugins.

Then maybe we have the same “problem” in those places.

>
> To me, the benefit of treating the COPY FORMAT value as a
> significant.

Really? You think lots of extensions are going to choose to use these
values even if they are permitted?  Or are you concerned about attack
surfaces?

> If those names can be shadowed by extension via

This is not a definition of backward-compatibility that I am familiar with.

If anything the ability for a DBA to arrange for such shadowing would be a
feature enhancement.  They can drop-in a more efficient or desirable
implementation without having to change query code.

In any case, I’m doubtful either of us can make a convincing enough
argument to sway the other fully.  Both options are plausible, IMO.  Others
need to chime in.

David J.

---

From: Sutou Kouhei <[email-masked]>
Date: Fri, 09 May 2025 17:51:27 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Fri, 2 May 2025 23:37:46 -0700,

>         LEFT JOIN pg_database D ON S.datid = D.oid;

Thanks. I didn't know about how to implement
pg_stat_progress_copy.

> the corresponding format name.

Does it work when we use session_preload_libraries or the
LOAD command? If we have 2 sessions and both of them load
"jsonlines" COPY FORMAT extensions, what will be happened?

For example:

1. Session 1: Register "jsonlines"
2. Session 2: Register "jsonlines"
              (Should global format ID <-> format name mapping
              be updated?)
3. Session 2: Close this session.
              Unregister "jsonlines".
              (Can we unregister COPY FORMAT extension?)
              (Should global format ID <-> format name mapping
              be updated?)
4. Session 1: Close this session.
              Unregister "jsonlines".
              (Can we unregister COPY FORMAT extension?)
              (Should global format ID <-> format name mapping
              be updated?)

Thanks,
-- 
kou

---

From: Sutou Kouhei <[email-masked]>
Date: Fri, 09 May 2025 18:41:37 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Sat, 3 May 2025 22:27:36 -0700,

> argument to sway the other fully.  Both options are plausible, IMO.  Others

I may misunderstand but here is the current summary, right?

Proposed approaches to register custom COPY formats:
a. Create a function that has the same name of custom COPY
   format
b. Call a register function from _PG_init()

FYI: I proposed c. approach that uses a. but it always
requires schema name for format name in other e-mail.

Users can register the same format name:
a. Yes
   * Users can distinct the same format name by schema name
   * If format name doesn't have schema name, the used
     format depends on search_path
     * Pros:
       * Using schema for it is consistent with other
         PostgreSQL mechanisms
       * Custom format never conflict with built-in
         format. For example, an extension register "xml" and
         PostgreSQL adds "xml" later, they are never
         conflicted because PostgreSQL's "xml" is registered
         to pg_catalog.
     * Cons: Different format may be used with the same
       input. For example, "jsonlines" may choose
       "jsonlines" implemented by extension X or implemented
       by extension Y when search_path is different.
b. No
   * Users can use "${schema}.${name}" for format name
     that mimics PostgreSQL's builtin schema (but it's just
     a string)

Built-in formats (text/csv/binary) should be able to
overwritten by extensions:
a. (The current patch is no but David's answer is) Yes
   * Pros: Users can use drop-in replacement faster
     implementation without changing input
   * Cons: Users may overwrite them accidentally.
     It may break pg_dump result.
     (This is called as "backward incompatibility.")
b. No

Are there any missing or wrong items? If we can summarize
the current discussion here correctly, others will be able
to chime in this discussion. (At least I can do it.)

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Fri, 9 May 2025 17:57:35 -0700

> I may misunderstand but here is the current summary, right?

Thank you for summarizing the discussion.

> requires schema name for format name in other e-mail.

With approach (c), do you mean that we require users to change all
FORMAT option values like from 'text' to 'pg_catalog.text' after the
upgrade? Or are we exempt the built-in formats?

>      (This is called as "backward incompatibility.")

The summary matches my understanding. I think the second point is
important. If we go with a tablesample-like API, I agree with David's
point that all FORMAT values including the built-in formats should
depend on the search_path value. While it provides a similar user
experience to other database objects, there is a possibility that a
COPY with built-in format could work differently on v19 than v18 or
earlier depending on the search_path value.

> Are there any missing or wrong items?

I think the approach (b) provides more flexibility than (a) in terms
of API design as with (a) we need to do everything based on one
handler function and callbacks.

> If we can summarize

+1

Regards,

---

From: Masahiko Sawada <[email-masked]>
Date: Fri, 9 May 2025 21:29:23 -0700

>               (Should global format ID <-> format name mapping

I imagine that only for progress reporting purposes, I think session 1
and 2 can have different format IDs for the same 'jsonlines' if they
load it by LOAD command. They can advertise the format IDs on the
shmem and we can also provide a SQL function for the progress view
that can get the format name by the format ID.

Considering the possibility that we might want to use the format ID
also in the cumulative statistics, we might want to strictly provide
the unique format ID for each custom format as the format IDs are
serialized to the pgstat file. One possible way to implement it is
that we manage the custom format IDs in a wiki page like we do for
custom cumulative statistics and custom RMGR[1][2]. That is, a custom
format extension registers the format name along with the format ID
that is pre-registered in the wiki page or the format ID (e.g. 128)
indicating under development. If either the format name or format ID
conflict with an already registered custom format extension, the
registration function raises an error. And we preallocate enough
format IDs for built-in formats.

As for unregistration, I think that  even if we provide an
unregisteration API, it ultimately depends on whether or not custom
format extensions call it in _PG_fini().

Regards,

[1] https://wiki.postgresql.org/wiki/CustomCumulativeStats
[2] https://wiki.postgresql.org/wiki/CustomWALResourceManagers

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Mon, 26 May 2025 10:04:05 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Fri, 9 May 2025 17:57:35 -0700,

> upgrade? Or are we exempt the built-in formats?

The latter. 'text' must be accepted because existing pg_dump
results use 'text'. If we reject 'text', it's a big
incompatibility. (We can't dump on old PostgreSQL and
restore to new PostgreSQL.)

> earlier depending on the search_path value.

Thanks for sharing additional points.

David said that the additional point case is a
responsibility or DBA not PostgreSQL, right?

As I already said, I don't have a strong opinion on which
approach is better. My opinion for the (important) second
point is no. I feel that the pros of a. isn't realistic. If
users want to improve text/csv/binary performance (or
something), they should improve PostgreSQL itself instead of
replacing it as an extension. (Or they should create another
custom copy format such as "faster_text" not "text".)

So I'm OK with the approach b.

> handler function and callbacks.

Thanks for sharing this missing point.

I have a concern that the flexibility may introduce needless
complexity. If it's not a real concern, I'm OK with the
approach b.

>> to chime in this discussion. (At least I can do it.)

Are there any more people who are interested in custom COPY
FORMAT implementation design? If no more people, let's
decide it by us.

Thanks,
-- 
kou

---

From: Sutou Kouhei <[email-masked]>
Date: Mon, 26 May 2025 10:27:20 +0900 (JST)

Hi,

In <CAD21AoAY_h-9nuhs14e3cyO_A2rH7==[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Fri, 9 May 2025 21:29:23 -0700,

> format extensions call it in _PG_fini().

Thanks for sharing your idea.

With the former ID issuing approach, it seems that we need a
global format ID <-> name mapping and a per session
registered format name list. The custom COPY FORMAT register
function rejects the same format name, right? If we support
both of shared_preload_libraries and
session_preload_libraries/LOAD, we have different life time
custom formats. It may introduce a complexity with the ID
issuing approach.

With the latter static ID approach, how to implement a
function that converts format ID to format name? PostgreSQL
itself doesn't know ID <-> name mapping in the Wiki page. It
seems that custom COPY FORMAT implementation needs to
register its name to PostgreSQL by itself.

Thanks,
-- 
kou

---

From: Michael Paquier <[email-masked]>
Date: Thu, 12 Jun 2025 11:33:52 +0900

> custom copy format such as "faster_text" not "text".)

Patches welcome.  Andres may have a TODO board regarding that, I
think.

> So I'm OK with the approach b.

Here is an opinion.

Approach (b), that uses _PG_init() a function to register a custom
format has the merit to be simple to implement and secure by "design",
because it depends only on the fact that we can do a lookup based on
the string defined in one or more DefElems.  Adding a dependendy to
search_path as you say could lead to surprising results. 

Using a shared ID when a COPY method is registered (like extension
wait events) or an ID that's static in a backend (like EXPLAIN
extensibility does) is an implementation difference that can be useful
for monitoring, and only that AFAIK.  If you want to implement
method-based statistics for COPY, you will want to allocate one stats
kind for each COPY method, because the stats stored will be aggregates
of the COPY methods.  The stats kind ID is something that should not
be linked to the COPY method ID, because the stats kind ID is
registered in its own dedicated path, and it would be hardcoded in the
library where the COPY callbacks are defined.  So you could have a
stats kind with a fixed ID, and a COPY method ID that's linked to each
backend like EXPLAIN does.

One factor to take into account is how much freedom we are OK with
giving to users when it comes to the deployment of custom COPY
methods, and how popular these would be.  Cloud is popular these days,
so folks may want to be able to define pointers to functions that are
run in something else than C, as long as the language is trusted.  My
take on this part is that we are not going to see many formats out
there that would benefit from these callbacks, so asking for people to
deploy a .so on disk that can only be LOAD'ed or registered with one
of the preloading GUCs should be enough to satisfy most users, even if
the barrier entry to get that only a cloud instead like RDS or Azure
is higher.  This has also the benefit in giving more control on the
COPY internals to cloud providers, as they are the ones who would be
in charge of saying if they're OK with a dedicated .so or not.  Not
the users themselves.  We've had a lot of bad PR and false CVEs in the
past with COPY FROM/TO PROGRAM and the fact that it requires
superusers.  Having something in this area that gives more freedom to
the user with something like approach (a) (SQL functions allowed to
define the callback) will, I suspect, bite us back hard.

So, my opinion is to rely on _PG_init(), with a shared ID if you want
to expose the method used somewhere for monitoring tools.  You could
as well implement the simpler set of APIs that allocates IDs local to
each backend, like EXPLAIN, then consider later if shared IDs are
really needed.  The registration APIs don't have to be fixed in time
across releases, they can be always improved in steps as required.
What matters is ABI compatibility in the same major version once it is
released.
--
Michael

---

From: Masahiko Sawada <[email-masked]>
Date: Thu, 12 Jun 2025 10:00:12 -0700

> > So I'm OK with the approach b.

Thank you for the comments.

> backend like EXPLAIN does.

Good point.

> define the callback) will, I suspect, bite us back hard.

That's a valid point and I agree.

> What matters is ABI compatibility in the same major version once it is

+1 to start with a simpler set of APIs.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Tue, 17 Jun 2025 08:50:37 +0900 (JST)

Hi,

In <CAD21AoBwxgfkMYxgPWyrLG-r8-ptVKjd=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Thu, 12 Jun 2025 10:00:12 -0700,

> +1 to start with a simpler set of APIs.

OK. I'll implement the initial version with this
design. (Allocating IDs local not shared.)

Thanks,
-- 
kou

---

From: Michael Paquier <[email-masked]>
Date: Tue, 17 Jun 2025 09:38:54 +0900

> design. (Allocating IDs local not shared.)

Sounds good to me.  Thanks Sutou-san!
--
Michael

---

From: Sutou Kouhei <[email-masked]>
Date: Wed, 18 Jun 2025 12:59:20 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Tue, 17 Jun 2025 09:38:54 +0900,

> Sounds good to me.  Thanks Sutou-san!

I've attached the v41 patch set that uses the C API approach
with local (not shared) COPY routine management.

0001: This is same as 0001 in the v40 patch set. It just
      cleans up CopySource and CopyDest enums.
0002: This is the initial version of this approach.

Here are some discussion points:

1. This provides 2 registration APIs
   (RegisterCopy{From,To}Routine(name, routine)) instead of
   1 registration API (RegisterCopyFormat(name,
   from_routine, to_routine)).

   It's for simple implementation and easy to extend without
   breaking APIs in the future. (And some formats may
   provide only FROM routine or TO routine.)

   Is this design acceptable?

   FYI: RegisterCopy{From,To}Routine() uses the same logic
   as RegisterExtensionExplainOption().

2. This allocates IDs internally but doesn't provide APIs
   that get them. Because it's not needed for now.

   We can provide GetExplainExtensionId() like API when we
   need it.
        
   Is this design acceptable?

3. I want to register the built-in COPY {FROM,TO} routines
   in the PostgreSQL initialization phase. Where should we
   do it? In 0002, it's done in InitPostgres() but I'm not
   sure whether it's a suitable location or not.

4. 0002 adds CopyFormatOptions::routine as union:

   @@ -87,9 +91,14 @@ typedef struct CopyFormatOptions
           CopyLogVerbosityChoice log_verbosity;   /* verbosity of logged messages */
           int64           reject_limit;   /* maximum tolerable number of errors */
           List       *convert_select; /* list of column names (can be NIL) */
   +       union
   +       {
   +               const struct CopyFromRoutine *from; /* for COPY FROM */
   +               const struct CopyToRoutine *to; /* for COPY TO */
   +       }                       routine;                /* routine to process the specified format */
    } CopyFormatOptions;

   Because one of Copy{From,To}Routine is only needed at
   once. Is this union usage strange in PostgreSQL?

5. 0002 adds InitializeCopy{From,To}Routines() and
   GetCopy{From,To}Routine() that aren't used by COPY
   {FROM,TO} routine implementations to copyapi.h. Should we
   move them to other .h? If so, which .h should be used for
   them?

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Tue, 24 Jun 2025 11:59:17 +0900

> 0002: This is the initial version of this approach.

Thank you for updating the patches!

>    Is this design acceptable?

With the single registration API idea, we can register the custom
format routine that supports only FROM routine using the API like:

RegisterCopyRoutine("new-format", NewFormatFromRoutine, NULL);

Compared to this approach, what points do you think having separate
two registration APIs is preferable in terms of extendability and API
compatibility? I think it would be rather confusing for example if
each COPY TO routine and COPY FROM routine is registered by different
extensions with the same format name.

>    as RegisterExtensionExplainOption().

I'm concerned that the patch has duplicated logics for the
registration of COPY FROM and COPY TO.

+1

>    sure whether it's a suitable location or not.

InitPostgres() is not a correct function as it's a process
initialization function. Probably we don't necessarily need to
register the built-in formats in the same way as custom formats. A
simple solution would be to have separate arrays for built-in formats
and custom formats and have the GetCopy[To|From]Routine() search both
arrays (built-in array first).

>    once. Is this union usage strange in PostgreSQL?

I think we can live with having two fields as there are other options
that are used only in either COPY FROM or COPY TO.

>    move them to other .h? If so, which .h should be used for

As I commented at 3, I think it's better to avoid dynamically
registering the built-in formats.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Tue, 24 Jun 2025 14:11:50 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Tue, 24 Jun 2025 11:59:17 +0900,
  Masahiko Sawada <[email-masked]> wrote:

> compatibility?

It's natural to add more related APIs with this
approach. The single registration API provides one feature
by one operation. If we use the RegisterCopyRoutine() for
FROM and TO formats API, it's not natural that we add more
related APIs. In this case, some APIs may provide multiple
features by one operation and other APIs may provide single
feature by one operation. Developers may be confused with
the API. For example, developers may think "what does mean
NULL here?" or "can we use NULL here?" for
"RegisterCopyRoutine("new-format", NewFormatFromRoutine,
NULL)".

>                I think it would be rather confusing for example if

Hmm, I don't think so. Who is confused by the case? DBA?
Users who use COPY? Why is it confused?

Do you assume the case that the same name is used for
different format? For example, "json" is used for JSON Lines
for COPY FROM and and normal JSON for COPY TO by different
extensions.

> registration of COPY FROM and COPY TO.

We can implement a convenient routine that can be used for
RegisterExtensionExplainOption() and
RegisterCopy{From,To}Routine() if it's needed.

> arrays (built-in array first).

We had a discussion that we should dog-food APIs:

https://www.postgresql.org/message-id/flat/CAKFQuwaCHhrS%2BRE4p_OO6d7WEskd9b86-2cYcvChNkrP%2B7PJ7A%40mail.gmail.com#e6d1cdd04dac53eafe34b784ac47b68b

> We should (and usually do) dog-food APIs when reasonable
> and this situation seems quite reasonable.

In this case, we don't need to dog-food APIs, right?

> that are used only in either COPY FROM or COPY TO.

OK.

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Tue, 24 Jun 2025 15:24:23 +0900

> "RegisterCopyRoutine("new-format", NewFormatFromRoutine,

We can document it in the comment for the registration function.

> for COPY FROM and and normal JSON for COPY TO by different

Suppose that extension-A implements only CopyToRoutine for the
custom-format-X with the format name 'myformat' and extension-B
implements only CopyFromRoutine for the custom-format-Y with the same
name, if users load both extension-A and extension-B, it seems to me
that extension-A registers the custom-format-X format as 'myformat'
only with CopyToRoutine, and extension-B overwrites the 'myformat'
registration by adding custom-format-Y's CopyFromRoutine. However, if
users register extension-C that implements both routines with the
format name 'myformat', they can register neither extension-A nor
extension-B, which seems to me that we don't allow overwriting the
registration in this case.

I think the core issue appears to be the internal management of custom
format entries but the current patch does enable registration
overwriting in the former case (extension-A and extension-B case).

> RegisterCopy{From,To}Routine() if it's needed.

I meant there are duplicated codes in COPY FROM and COPY TO. For
instance, RegisterCopyFromRoutine() and RegisterCopyToRoutine() have
the same logic.

> In this case, we don't need to dog-food APIs, right?

Yes, I think so.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Tue, 24 Jun 2025 16:10:09 +0900 (JST)

Hi,

In <CAD21AoC8-d=GF-hOvGqUyq2xFg=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Tue, 24 Jun 2025 15:24:23 +0900,

> We can document it in the comment for the registration function.

I think that API that can be understandable without the
additional note is better API than API that needs some
notes.

Why do you suggest the RegisterCopyRoutine("new-format",
NewFormatFromRoutine, NewFormatToRoutine) API? You want to
remove the duplicated codes in
RegisterCopy{From,To}Routine(), right? I think that we can
do it by creating a convenient function that has the
duplicated codes extracted from
RegisterCopy{From,To}Routine() and
RegisterExtensionExplainOption().

BTW, what do you think about my answer (one feature by one
operation API is more extendable API) for your question
(extendability and API compatibility)?

> registration in this case.

Do you assume that users use extension-A, extension-B and
extension-C without reading their documentation? If users
read their documentation before users use them, users can
know all of them use the same format name 'myformat' and
which extension provides Copy{From,To}Routine.

In this case, these users (who don't read documentation)
will be confused with the RegisterCopyRoutine("new-format",
NewFormatFromRoutine, NewFormatToRoutine) API too. Do we
really need to care about this case?

> overwriting in the former case (extension-A and extension-B case).

This is the same behavior as existing custom EXPLAIN option
implementation. Should we use different behavior here?

> instance, RegisterCopyFromRoutine() and RegisterCopyToRoutine() have

Yes, I understand it. I wanted to say that we can remove the
duplicated codes by introducing a RegisterSomething()
function that can be used by
RegisterExtensionExplainOption() and
RegisterCopy{From,To}Routine():

void
RegisterSomething(...)
{
  /* Common codes in RegisterExtensionExplainOption() and
     RegisterCopy{From,To}Routine()
     ...
   */
}

void
RegisterExtensionExplainOption(...)
{
  RegisterSomething(...);
}

void
RegisterCopyFromRoutine(...)
{
  RegisterSomething(...);
}

void
RegisterCopyToRoutine(...)
{
  RegisterSomething(...);
}

You think that this approach can't remove the duplicated
codes, right?

>> In this case, we don't need to dog-food APIs, right?

OK. I don't have a strong opinion for it. If nobody objects
it, I'll do it when I update the patch set.

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Wed, 25 Jun 2025 00:48:46 +0900

> additional note is better API than API that needs some

I don't see much difference in this case.

> RegisterCopy{From,To}Routine(), right?

No. I think that if extensions are likely to support both
CopyToRoutine and CopyFromRoutine in most cases, it would be simpler
to register the custom format using a single API. Registering
CopyToRoutine and CopyFromRoutine separately seems redundant to me.

> (extendability and API compatibility)?

Could you provide some examples? It seems to me that even if we
provide the single API for the registration we can provide other APIs
differently. For example, if we want to provide an API to register a
custom option, we can provide RegisterCopyToOption() and
RegisterCopyFromOption().

> really need to care about this case?

My point is about the consistency of registration behavior. I think
that we should raise an error if the custom format name that an
extension tries to register already exists. Therefore I'm not sure why
installing extension-A+B is okay but installing extension-C+A or
extension-C+B is not okay? We can think that's an extension-A's choice
not to implement CopyFromRoutine for the 'myformat' format so
extension-B should not change it.

> implementation. Should we use different behavior here?

I think that unlike custom EXPLAIN options, it's better to raise an
error or a warning if the custom format name (or combination of format
name and COPY direction) that an extension tries to register already
exists.

> You think that this approach can't remove the duplicated

Well, no, I just meant we don't need to do that. Custom EXPLAIN option
and custom COPY format are different features and have different
requirements. I think while we don't need to remove duplicates between
them at least at this stage we need to remove the duplicate between
COPY TO registration code and COPY TO's one.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Wed, 25 Jun 2025 16:35:47 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Wed, 25 Jun 2025 00:48:46 +0900,

> I don't see much difference in this case.

OK. It seems that we can't agree on which API is better.

I've implemented your idea as the v42 patch set. Can we
proceed this proposal with this approach? What is the next
step?

> CopyToRoutine and CopyFromRoutine separately seems redundant to me.

I don't think so. In general, extensions are implemented
step by step. Extension developers will not implement
CopyToRoutine and CopyFromRoutine at once even if extensions
implement both of CopyToRoutine and CopyFromRoutine
eventually.

> RegisterCopyFromOption().

Yes. We can mix different style APIs. In general, consistent
style APIs is easier to use than mixed style APIs. If it's
not an important point in PostgreSQL API design, my point is
meaningless. (Sorry, I'm not familiar with PostgreSQL API
design.)

> extension-B should not change it.

I think that it's the users' responsibility. I think that
it's more convenient that users can mix extension-A+B (A
provides only TO format and B provides only FROM format)
than users can't mix them. I think that extension-A doesn't
want to prohibit FROM format in the case. Extension-A just
doesn't care about FROM format.

FYI: Both of extension-C+A and extension-C+B are OK when we
update not raising an error existing format.

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Mon, 30 Jun 2025 15:00:45 +0900

> proceed this proposal with this approach? What is the next

I'll review the patches. In the meanwhile could you update the
documentation accordingly?

> implement both of CopyToRoutine and CopyFromRoutine

Hmm, I think if the extension eventually implements both directions,
it would make sense to provide the single API.

> meaningless. (Sorry, I'm not familiar with PostgreSQL API

As far as I know, there is no standard for PostgreSQL API design, but
I don't find any weirdness in this design.

> update not raising an error existing format.

I want to keep the basic design that one custom format comes from one
extension because it's straightforward for both of us and users and
easy to maintain format ID. IIUC we somewhat agreed on this design in
the previous API design (TABLESAMPLE like API).

Regards,

---

From: Masahiko Sawada <[email-masked]>
Date: Mon, 14 Jul 2025 03:28:16 +0900

On Mon, Jun 30, 2025 at 3:00 PM Masahiko Sawada <[email-masked]> wrote:
> I'll review the patches.

I've reviewed the 0001 and 0002 patches. The API implemented in the
0002 patch looks good to me, but I'm concerned about the capsulation
of copy state data. With the v42 patches, we pass the whole
CopyToStateData to the extension codes, but most of the fields in
CopyToStateData are internal working state data that shouldn't be
exposed to extensions. I think we need to sort out which fields are
exposed or not. That way, it would be safer and we would be able to
avoid exposing copyto_internal.h and extensions would not need to
include copyfrom_internal.h.

I've implemented a draft patch for that idea. In the 0001 patch, I
moved fields that are related to internal working state from
CopyToStateData to CopyToExectuionData. COPY routine APIs pass a
pointer of CopyToStateData but extensions can access only fields
except for CopyToExectuionData. In the 0002 patch, I've implemented
the registration API and some related APIs based on your v42 patch.
I've made similar changes to COPY FROM codes too.

The patch is a very PoC phase and we would need to scrutinize the
fields that should or should not be exposed. Feedback is very welcome.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Mon, 14 Jul 2025 17:38:03 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Mon, 14 Jul 2025 03:28:16 +0900,

> include copyfrom_internal.h.

FYI: We discussed this so far. For example:

https://www.postgresql.org/message-id/flat/CAD21AoD%3DUapH4Wh06G6H5XAzPJ0iJg9YcW8r7E2UEJkZ8QsosA%40mail.gmail.com

> I think we can move CopyToState to copy.h and we don't
> need to have set/get functions for its fields.

https://www.postgresql.org/message-id/flat/CAD21AoBpWFU4k-_bwrTq0AkFSAdwQqhAsSW188STmu9HxLJ0nQ%40mail.gmail.com

> > What does "private" mean here? I thought that it means that
> > "PostgreSQL itself can use it". But it seems that you mean
> > that "PostgreSQL itself and custom format extensions can use
> > it but other extensions can't use it".
> >
> > I'm not familiar with "_internal.h" in PostgreSQL but is
> > "_internal.h" for the latter "private" mean?
>
> My understanding is that we don't strictly prohibit _internal.h from
> being included in out of core files. For example, file_fdw.c includes
> copyfrom_internal.h in order to access some fields of CopyFromState.

In general, I agree that we should export only needed
information.

How about adding accessors instead of splitting
Copy{From,To}State to Copy{From,To}ExecutionData? If we use
the accessors approach, we can export only needed
information step by step without breaking ABI.

The built-in formats can keep using Copy{From,To}State
directly with the accessors approach. We can avoid any
performance regression of the built-in formats. If we split
Copy{From,To}State to Copy{From,To}ExecutionData,
performance may be changed.

> fields that should or should not be exposed. Feedback is very welcome.

Based on our sample extensions [1][2], the following fields
may be minimal. I added "(*)" marks that exist in
Copy{From,To}StateDate in your patch. Other fields exist in
Copy{From,To}ExecutionData. We need to export them to
extensions. We can hide fields in Copy{From,To}StateData not
listed here.

FROM:

- attnumlist (*)
- bytes_processed
- cur_attname
- escontext
- in_functions (*)
- input_buf
- input_reached_eof
- line_buf
- opts (*)
- raw_buf
- raw_buf_index
- raw_buf_len
- rel (*)
- typioparams (*)

TO:

- attnumlist (*)
- fe_msgbuf
- opts (*)

[1] https://github.com/kou/pg-copy-arrow/
[2] https://github.com/MasahikoSawada/pg_copy_jsonlines/

Thanks,
-- 
kou

---

From: Sutou Kouhei <[email-masked]>
Date: Tue, 15 Jul 2025 16:54:13 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Mon, 14 Jul 2025 17:38:03 +0900 (JST),

> information step by step without breaking ABI.

Another idea: We'll add Copy{From,To}State::opaque
eventually. (For example, the v40-0003 patch includes it.)

How about using it to hide fields only for built-in formats?

Thanks,
-- 
kou

---

From: Andres Freund <[email-masked]>
Date: Tue, 15 Jul 2025 08:36:58 -0400

Hi,

> I've made similar changes to COPY FROM codes too.

I've not followed the development of this patch - but I continue to be
concerned about the performance impact it has as-is and the amount of COPY
performance improvements it forecloses.

This seems to add yet another layer of indirection to a lot of hot functions
like CopyGetData() etc.

Greetings,

Andres Freund

---

From: Masahiko Sawada <[email-masked]>
Date: Thu, 17 Jul 2025 13:33:13 -0700

> This seems to add yet another layer of indirection to a lot of hot functions

The most refactoring works have been done by commit 7717f6300 and
2e4127b6d with a slight performance gain. At this stage, we're trying
to introduce the registration API so that extensions can provide their
callbacks to the core. Some functions required for I/O such as
CopyGetData() and CopySendEndOfRow() would be exposed but I'm not
going to add additional indirection function call layers.

Regards,

---

From: Masahiko Sawada <[email-masked]>
Date: Thu, 17 Jul 2025 13:44:11 -0700

> > information step by step without breaking ABI.

Yeah, while it can export required fields without breaking ABI, I'm
concerned that setter and getter functions could be bloated if we need
to have them for many fields.

> How about using it to hide fields only for built-in formats?

What is the difference between your idea and splitting CopyToState
into CopyToState and CopyToExecutionData?

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Fri, 18 Jul 2025 18:49:12 +0900 (JST)

Hi,

In <CAD21AoAQkjU=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Thu, 17 Jul 2025 13:33:13 -0700,

> going to add additional indirection function call layers.

I think Andres is talking about any indirection not only
indirection function call. In this case, "cstate->XXX" ->
"cstate->edata->XXX".

It's also mentioned in my e-mail. I'm not sure whether it
has performance impact but it's better that we benchmark to
confirm whether there is any performance impact or not with
the Copy{From,To}ExecutionData approach.

Thanks,
-- 
kou

---

From: Sutou Kouhei <[email-masked]>
Date: Fri, 18 Jul 2025 19:05:53 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Thu, 17 Jul 2025 13:44:11 -0700,

> to have them for many fields.

In general, I choose this approach in my projects even when
I need to define many accessors. Because I can hide
implementation details from users. I can change
implementation details without breaking API/ABI.

But PostgreSQL isn't my project. Is there any guideline for
PostgreSQL API(/ABI?) design that we can refer for this
case?

FYI: We need to export at least the following fields:

https://www.postgresql.org/message-id/flat/20250714.173803.865595983884510428.kou%40clear-code.com#78fdbccf89742f856aa2cf95eaf42032

> - opts (*)

Here are pros/cons of the Copy{From,To}ExecutionData
approach, right?

Pros:
1. We can hide internal data from extensions

Cons:
1. Built-in format routines need to refer fields via
   Copy{From,To}ExecutionData.
   * This MAY has performance impact. If there is no
     performance impact, this is not a cons.
2. API/ABI compatibility will be broken when we change
   exported fields.
   * I'm not sure whether this is a cons in the PostgreSQL
     design.

Here are pros/cons of the accessors approach:

Pros:
1. We can hide internal data from extensions
2. We can export new fields change field names
   without breaking API/ABI compatibility
3. We don't need to change built-in format routines.
   So we can assume that there is no performance impact.

Cons:
1. We may need to define many accessors
   * I'm not sure whether this is a cons in the PostgreSQL
     design.

> into CopyToState and CopyToExecutionData?

1. We don't need to manage 2 similar data for built-in
   formats and extensions.
   * Build-in formats use CopyToExecutionData and extensions
     use opaque.
2. We can introduce registration API now.
   * We can work on this topic AFTER we introduce
     registration API.
   * e.g.: Add registration API -> Add opaque -> Use opaque
     for internal fields (we will benchmark this
     implementation at this time)

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Mon, 28 Jul 2025 12:33:28 -0700

> PostgreSQL API(/ABI?) design that we can refer for this

As far as I know there is no official guideline for PostgreSQL API and
ABI design, but I've never seen structs having more than 10 getter and
setter in PostgreSQL source code.

> https://www.postgresql.org/message-id/flat/20250714.173803.865595983884510428.kou%40clear-code.com#78fdbccf89742f856aa2cf95eaf42032

I think we can think of the minimum list of fields that we need to
expose. For instance, fields used for buffered reads for COPY FROM
such as input_buf and raw_buf related fields don't necessarily need to
be exposed as extension can implement it in its own way. We can start
with the supporting simple copy format extensions like that read and
parse the binary data from the data source and fill 'values' and
'nulls' arrays as output. Considering these facts, it might be
sufficient for copy format extensions if they could access 'rel',
'attnumlist', and 'opts' in both COPY FROM and COPY TO (and
CopyFromErrorCallback related fields for COPY FROM).

Apart from this, we might want to reorganize CopyFromStateData fields
and CopyToStateData fields since they have mixed fields of general
purpose fields for COPY operations (e.g., num_defaults, whereClause,
and range_table) and built-in format specific fields (e.g., line_buf
and input_buf). Text and CSV formats are using some fields for parsing
fields with buffered reads so one idea is that we move related fields
to another struct so that both built-in formats (text and CSV) and
external extensions that want to use the buffered reads for text
parsing can use this functionality.

>    * I'm not sure whether this is a cons in the PostgreSQL

I agree with the summary.

>      implementation at this time)

What if we find performance overhead in built-in format cases after
introducing opaque data? I personally would like to avoid merging the
registration API (i.e., supporting custom copy formats) while being
unsure about the overall design ahead and the potential performance
impact by following patches.

Regards,

---

From: Masahiko Sawada <[email-masked]>
Date: Mon, 28 Jul 2025 22:19:36 -0700

> parsing can use this functionality.

So probably it might be worth refactoring the codes in terms of:

1. hiding internal data from format callbacks
2. separating format-specific fields from the main state data.

I categorized the fields in CopyFromStateData. I think there are
roughly three different kind of fields mixed there:

1. fields used only the core (not by format callback)
- filename
- is_program
- whereClause
- cur_relname
- copycontext
- defmap
- num_defaults
- volatile_defexprs
- range_table
- rtrperminfos
- qualexpr
- transition_capture

2. fields used by both the core and format callbacks
- rel
- attnumlist
- cur_lineno
- cur_attname
- cur_attval
- relname_only
- num_errors
- opts
- in_functions
- typioparams
- escontext
- defexprs
- Input-related fields
    - copy_src
    - copy_file
    - fe_msgbuf
    - data_source_cb
    - byteprocessed

3. built-in format specific fields (mostly for text and csv)
- eol_type
- defaults
- Encoding related fields
    - file_encoding
    - need_transcoding
    - conversion_proc
- convert_select_flags
- raw data pointers
    - max_fields
    - raw_fields
- attribute_buf
- line_buf related fields
    - line_buf
    - line_buf_valid
- input_buf related fields
    - input_buf
    - input_buf_index
    - input_buf_len
    - input_reached_eof
    - input_reached_error
- raw_buf related fields
    - raw_buf
    - raw_buf_index
    - raw_buf_len
    - raw_reached_eof

The fields in 1 are mostly static fields, and the fields in 2 and 3
are likely to be accessed in hot functions during COPY FROM. Would it
be a good idea to restructure these fields so that we can hide the
fields in 1 from callback functions and having the fields in 3 in a
separate format-specific struct that can be accessed via an opaque
pointer? But could the latter change potentially cause performance
overheads?

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Thu, 14 Aug 2025 15:36:54 +0900 (JST)

Hi,

In <CAD21AoBa0Wm3C2H12jaqkvLidP2zEhsC+gf=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Mon, 28 Jul 2025 22:19:36 -0700,

> pointer? But could the latter change potentially cause performance

Yes. It changes memory layout (1 continuous memory chunk ->
2 separated memory chunks) and introduces indirect member
accesses (x->y -> x->z->y). They may not have performance
impact but we need to measure it if we want to use this
approach.

BTW, how about the following approach?

copyapi.h:

typedef struct CopyToStateData
{
	/* public members */
	/* ... */
} CopyToStateData;

copyto.c:

typedef struct CopyToStateInternalData
{
	CopyToStateData parent;

	/* private members */
	/* ... */
} CopyToStateInternalData;

We export CopyToStateData only with public members. We don't
export CopyToStateInternalData that has members only for
built-in formats.

CopyToStateInternalData has the same memory layout as
CopyToStateData. So we can use CopyToStateInternalData as
CopyToStateData.

We use CopyToStateData not CopyToStateInternalData in public
API. We cast CopyToStateData to CopyToStateInternalData when
we need to use private members:

static void
CopySendData(CopyToState cstate, const void *databuf, int datasize)
{
	CopyToStateInternal cstate_internal = (CopyToStateInternal) cstate;
	appendBinaryStringInfo(cstate_internal->fe_msgbuf, databuf, datasize);
}

It's still direct member access.

With this approach, we can keep the same memory layout (1
continuous memory chunk) and direct member access. I think
that this approach doesn't have performance impact.

See the attached patch for PoC of this approach.

Drawback: This approach always allocates
CopyToStateInternalData not CopyToStateData. So we need to
allocate needless memories for extensions. But this will
prevent performance regression of built-in formats. Is it
acceptable?

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Mon, 8 Sep 2025 14:08:16 -0700

On Wed, Aug 13, 2025 at 11:37 PM Sutou Kouhei <[email-masked]> wrote:
> accesses (x->y -> x->z->y).

I think fields accessed by the hot functions are limited. If we
assemble fields required by hot functions into one struct and pass it
to them can we deal with the latter? For example, we assemble the
fields in 3 I mentioned above (i.e., built-in format specific fields)
into say CopyFromStateBuiltin and pass it to CopyReadLine() function
and the following functions, instead of CopyFromState. Since there are
some places where we need to access to CopyFromState (e.g.,
CopyGetData()), CopyFromStateBuiltin needs to have a pointer to
CopyFromState as well.

>  They may not have performance

Agreed.

> prevent performance regression of built-in formats. Is it

While this approach could make sense to avoid potential performance
overheads for built-in format, I find it's somewhat odd that
extensions cannot allocate memory for its working state having
CopyToStateData as the base type.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Tue, 09 Sep 2025 11:50:14 +0900 (JST)

Hi,

In <CAD21AoCCjKA77xkUxx59qJ8an_G_58Mry_EtCEcFgd=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Mon, 8 Sep 2025 14:08:16 -0700,

> CopyGetData()), CopyFromStateBuiltin needs to have a pointer to

It can change indirect member accesses (built-in format
specific members can be direct access but other members in
CopyFromState are indirect access) but it doesn't change 2
separated memory chunks.

If this approach has performance impact and it's caused by
indirect member accesses for built-in format specific
members, your suggestion will work. If performance impact is
caused by another reason, your suggestion may not work.

Anyway, we need to measure performance to proceed with this
approach. If we can confirm that this approach doesn't have
any performance impact, we can use the original your idea.

Do you have any idea how to measure performance of this
approach?

We did it when we introduce Copy{To,From}Routine. But it was
difficult to evaluate the results:

* I don't have machines for stable benchmark results
  * We may not be able to use them for the final decision
* Most results showed performance improvement but
  there was a result showed mysterious result[1]

[1] https://www.postgresql.org/message-id/flat/CAEG8a3LUBcvjwqgt6AijJmg67YN_b_NZ4Kzoxc_dH4rpAq0pKg%40mail.gmail.com

> CopyToStateData as the base type.

Is it important? We'll provide a opaque member for
extensions. Extensions should use the opaque member instead
of extending Copy{From,To}StateData.

I don't object your approach but we need a good way to
measure performance. If we use this approach, we can omit it
for now and we can revisit your approach later without
breaking compatibility. How about using this approach if we
can't find a good way to measure performance?

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Tue, 9 Sep 2025 13:15:43 -0700

> CopyFromState are indirect access) but it doesn't change 2

Right. IIUC the latter point is related to cache locality. But I'm not
sure how much the latter point affects the performance as currently we
don't declare fields to CopyFromState while carefully considering the
cache locality even today. Separating a single memory into multiple
chunks could even have a positive effect on it.

> Do you have any idea how to measure performance of this

I think we can start with measuring the entire COPY execution time
with several scenarios as we did previously. For example, reading a
huge file with a single column value and with many columns etc.

>   there was a result showed mysterious result[1]

Perhaps measuring cache-misses help to see how changes could affect
the performance?

> of extending Copy{From,To}StateData.

I think yes, because it could be a blocker for future improvements
that might require a large field to CopyFrom/ToStateData.

> can't find a good way to measure performance?

I think it would be better to hear more opinions about this idea and
then make a decision, rather than basing our decision on whether or
not we can measure its performance, so we can be more confident in the
idea we have chosen. While this idea has the above downside, it could
make sense because we always allocate the entire CopyFrom/ToStateData
even today in spite of some fields being not used at all in binary
format and it requires less implementation costs to hide the
for-core-only fields. On the other hand, another possible idea is that
we have three different structs for categories 1 (core-only), 2 (core
and extensions), and 3 (extension-only), and expose only 2 that has a
void pointer to 3. The core can allocate the memory for 1 that embeds
2 at the beginning of the fields. While this design looks cleaner and
we can minimize overheads due to indirect references, it would require
more implementation costs. Which method we choose, I think we need
performance measurements in several scenarios to check if performance
regressions don't happen unexpectedly.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Wed, 10 Sep 2025 11:40:58 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Tue, 9 Sep 2025 13:15:43 -0700,

> regressions don't happen unexpectedly.

OK. So the next step is collecting more opinions, right?

Could you add key people in this area to Cc to hear their
opinions? I'm not familiar with key people in the PostgreSQL
community...

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Wed, 10 Sep 2025 00:36:38 -0700

> opinions? I'm not familiar with key people in the PostgreSQL

How about another idea like we move format-specific data to another
struct that embeds CopyFrom/ToStateData at the first field and have
CopyFrom/ToStart callback return memory with the size of that
struct?It resolves the concerns about adding an extra indirection
layer and extensions doesn't need to allocate memory for unnecessary
fields (used only for built-in formats). While extensions can access
the internal fields I think we can live with that given that there are
some similar precedents such as table AM's scan descriptions.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Thu, 11 Sep 2025 14:46:27 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Wed, 10 Sep 2025 00:36:38 -0700,

> some similar precedents such as table AM's scan descriptions.

The another idea looks like the following, right?

struct CopyToStateBuiltInData
{
  struct CopyToStateData parent;

  /* Members for built-in formats */
  ...;
}

typedef CopyToState *(*CopyToStart) (void);

CopyToState
BeginCopyTo(..., CopyToStart copy_to_start)
{
  ...;

  /* Allocate workspace and zero all fields */
  cstate = copy_to_start();
  ...;
}

This idea will almost work. But we can't know which
CopyToStart should be used before we parse "FORMAT" option
of COPY.

If we can iterate options twice in BeginCopy{To,From}(), we
can know it. For example:

BeginCopyTo(...)
{
  ...;

  CopyToStart copy_to_start = NULL;
  foreach(option, options)
  {
    DefElem  *defel = lfirst_node(DefElem, option);

    if (strcmp(defel->defname, "format") == 0)
    {
       char *fmt = defGetString(defel);
       if (strcmp(fmt, "text") == 0 ||
           strcmp(fmt, "csv") == 0 ||
           strcmp(fmt, "binary") == 0) {
         /* Use the builtin cstate */
       } else {
         copy_to_start = /* Detect CopyToStart for custom format */;
       }
    }
  }
  if (copy_to_start)
    cstate = copy_to_start();
  else 
    cstate = (CopyToStateData *) palloc0(sizeof(CopyToStateBuiltInData));
  ...;
}

(It may be better that we add
Copy{To,From}Routine::Copy{To,From}Allocate() instead of
CopyToStart callback.)

I think that this is acceptable because this must be a light
process. This must not have negative performance impact.

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Thu, 11 Sep 2025 13:41:26 -0700

>   cstate = copy_to_start();

Right.

> Copy{To,From}Routine::Copy{To,From}Allocate() instead of

I think we can use a local variable of CopyFormatOptions and memcpy it
to the opts of the returned cstate.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Fri, 12 Sep 2025 09:07:52 +0900 (JST)

Hi,

In <CAD21AoCfqD=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Thu, 11 Sep 2025 13:41:26 -0700,

> to the opts of the returned cstate.

It'll work too. Can we proceed this proposal with this
approach? Should we collect more opinions before we proceed?
If so, Could you add key people in this area to Cc to hear
their opinions?

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Mon, 15 Sep 2025 10:00:18 -0700

> If so, Could you add key people in this area to Cc to hear

Since we don't have a single decision-maker, we should proceed through
consensus-building and careful evaluation of each approach. I see that
several senior hackers are already included in this thread, which is
excellent. Since you and I, who have been involved in these
discussions, agreed with this approach, I believe we can proceed with
this direction. If anyone proposes alternative solutions that we find
more compelling, we might have to change the approach.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Fri, 03 Oct 2025 16:06:50 +0900 (JST)

Hi,

In <CAD21AoADXWgdizS0mV5w8wdfftDRsm8sUtNW=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Mon, 15 Sep 2025 10:00:18 -0700,

> more compelling, we might have to change the approach.

OK. There is no objection for now.

How about the attached patch? The patch uses the approach
only for CopyToStateData. If this looks good, I can do it
for CopyFromStateData too.

This patch splits CopyToStateData to

* CopyToStateData
* CopyToStateInternalData
* CopyToStateBuiltinData

structs.

This is based on the category described in
https://www.postgresql.org/message-id/flat/CAD21AoBa0Wm3C2H12jaqkvLidP2zEhsC%2Bgf%3D3w7XiA4LQnvx0g%40mail.gmail.com#85cb988b0bec243d1e8dce699e02e009

> 3. built-in format specific fields (mostly for text and csv)

CopyToStateInternalData is for 1.
CopyToStateData is for 2.
CopyToStateBuiltinData is for 3.

This patch adds CopyToRoutine::CopyToGetStateSize() that
returns size of state struct for the routine. For example,
Built-in formats use sizeof(CopyToStateBuiltinData) for it.

BeginCopyTo() allocates sizeof(CopyToStateInternalData) +
CopyToGetStateSize() size continuous memory and uses the
front part as CopyToStateInternalData and the back part as
CopyToStateData/CopyToStateBuilinData.

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Mon, 13 Oct 2025 14:40:31 -0700

> CopyToStateData/CopyToStateBuilinData.

Thank you for drafting the idea!

The patch refactors the CopyToStateData so that we can both hide
internal-use-only fields from extensions and extension can use its own
state data, while not adding extra indirection layers. TBH I'm really
not sure we must fully hide internal fields from extensions. Other
extendable components seem not to strictly hide internal information
from extensions. I'd suggest starting with only the latter point. That
is, we merge fields in CopyToStateInternalData to CopyToStateData.
What do you think?

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Tue, 14 Oct 2025 11:15:24 +0900 (JST)

Hi,

In <CAD21AoBkA=g=[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Mon, 13 Oct 2025 14:40:31 -0700,

> is, we merge fields in CopyToStateInternalData to CopyToStateData.

OK. Let's follow the existing style. How about the attached
patch? It merges CopyToStateInternalData to CopyToStateData.

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Wed, 29 Oct 2025 13:41:39 -0700

> patch? It merges CopyToStateInternalData to CopyToStateData.

The basic idea of this patch makes sense to me.

Andres, I believe that the current idea deals with your concerns about
performance overheads. Particularly, we separate format-specific
fields (c.f. CopyToStateBuiltinData struct in the patch) from the
commonly-used fields (c.f., CopyToStateData struct), but the whole
fields are stored in the contiguous memory. While the patch needs to
be polished much, could you review if the basic idea of this patch
addresses your concern?

Regards,

---

From: Masahiko Sawada <[email-masked]>
Date: Fri, 14 Nov 2025 12:19:47 -0800

> The basic idea of this patch makes sense to me.

This thread has involved extensive discussion, and the patch needs to
be rebased. I'd like to summarize the current status of this patch and
our discussions. I've attached updated patches that implement the
whole ideas of this feature to help provide a clearer overall picture.

In commits 2e4127b6d and 7717f6300, we refactored COPY TO/FROM code to
use a set of callbacks for format-specific operations like data
parsing. These callbacks are currently not exposed and are only used
by built-in formats. The next step is to allow extensions to register
their own format implementations, which these attached patches
accomplish. The registration API can be called in _PG_init() as
follows to enable users to specify a custom format name ('jsonlines'
in this example) in the FORMAT option:

RegisterCopyCustomFormat("jsonlines",
                       &JsonLinesCopyFromRoutine,
                       &JsonLinesCopyToRoutine);

However, before introducing the registration API, we need to resolve
an issue with how we currently use a monolithic struct
(Copy{From,To}StateData) to store COPY TO/FROM state data. This struct
currently contains both format-agnostic fields (e.g., target relation
and source file) and format-specific fields (e.g., input buffers and
EOL type). Patches 0001 and 0002 reorganize these fields to separate
them. Specifically, format-specific fields are moved to a new struct
while Copy{From,To}StateData retains format-agnostic fields, as shown
here (e.g., COPY TO case):

typedef struct CopyToStateData
{
    /* format-specific routines */
    const struct CopyToRoutine *routine;

    /* low-level state data */
    CopyDest    copy_dest;      /* type of copy source/destination */
    FILE       *copy_file;      /* used if copy_dest == COPY_DEST_FILE */
    StringInfo  fe_msgbuf;      /* used for all dests during COPY TO */

    (snip)

    /*
     * Working state
     */
    MemoryContext copycontext;  /* per-copy execution context */

typedef struct CopyToStateTextLike
{
    CopyToStateData base; /* embedded */

    int             file_encoding;
    bool            need_transcoding;
    bool            encoding_embeds_ascii;
} CopyToStateTextLike;

Extensions must specify their required state struct size (like
CopyToStateTextLike for built-in formats) using new callbacks
Copy{From,To}EstimateStateSpace, allowing the core to allocate the
appropriate amount of memory. This approach offers two advantages:

- Format processing implementations only use the memory they need
- No additional pointer traversal compared to using an opaque pointer
for format-specific data

Patches 0003 through 0006 implement the following:

0003: Introduces the RegisterCustomCopyFormat() API
0004 and 0005: Enable custom format implementations to register their
own COPY command options
0006: Adds regression tests

 With these patches, here's what we can do using the 'jsonlines'
format extension:

-- COPY TO
CREATE TABLE jl (id int, a text, b jsonb);
INSERT INTO jl VALUES (1, 'hello', '{"test" : [1, true, {"num" :
42}]}'::jsonb), (2, 'hello world', 'true'), (999, null, '{"a" : 1}');
TABLE jl;
 id  |      a      |                b
-----+-------------+----------------------------------
   1 | hello       | {"test": [1, true, {"num": 42}]}
   2 | hello world | true
 999 |             | {"a": 1}
(3 rows)

COPY jl TO '/tmp/test.jsonl' WITH (format 'jsonlines');
\! cat /tmp/test.jsonl
{"id":1,"a":"hello","b":{"test": [1, true, {"num": 42}]}}
{"id":2,"a":"hello world","b":true}
{"id":999,"a":null,"b":{"a": 1}}

-- COPY FROM
CREATE TABLE jl_load (id int, a text, b jsonb);
COPY jl_load FROM '/tmp/test.jsonl' WITH (format 'jsonlines');

-- COPY TO/FROM with custom options
COPY jl TO '/tmp/jl.jsonl.gz' WITH (format 'jsonlines', compression
'gzip', compression_detail 'level=2');
COPY jl FROM '/tmp/jl.jsonl.gz' WITH (format 'jsonlines');

To demonstrate the functionality of both current and new APIs,
Suto-san and I have created several experimental custom COPY format
extensions:

Apache Arrow (developed by Sutou-san): https://github.com/kou/pg-copy-arrow

JSON Lines (developed by me):
https://github.com/MasahikoSawada/pg_custom_copy_formats/blob/master/jsonlines.c

These implementations serve as good examples of how extensions can use
these APIs to define custom COPY formats.

After offline discussions with Sutou-san, we believe the current APIs
work well, particularly for text-based formats, though we still need
to verify there are no performance regressions.

One potential improvement would be adding support for random file
access in COPY FROM operations. For example, with parquet files, it
would be much more efficient to read the footer section first since it
contains metadata, allowing selective reading of necessary file
sections. The current sequential read API (CopyFromGetData()) requires
reading all data to access the metadata.

For future consideration, we could look into supporting file
reading/writing from external sources like S3. While this is outside
the scope of this patch, we discussed that allowing the core to
delegate I/O operations to custom format implementations might be a
good starting point. We can discuss this in a separate thread.

I welcome your feedback on these proposed changes and APIs to help
move this patch forward.

Regards,

---

From: Sutou Kouhei <[email-masked]>
Date: Mon, 17 Nov 2025 15:40:13 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Fri, 14 Nov 2025 12:19:47 -0800,

Thanks!

I'm not sure whether we should include option parsing
feature to this patch's scope or not but I'm OK with this
approach.

Here are my review comments but they are minor
comments. They don't require design change.

0001:

diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index cef452584e5..6a0a66507ba 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -155,6 +120,7 @@ static void CopySendInt16(CopyToState cstate, int16 val);
 
 /* text format */
 static const CopyToRoutine CopyToRoutineText = {
+	.CopyToEstimateStateSpace = CopyToEstimateStateTextLike,

How about including "Space"
(CopyToEstimateStateSpaceTextLike)?

How about renaming this to
"CopyToTextLikeEstimateStateSpace" because other functions
use "CopyToTextLikeXXX" style.

@@ -171,62 +138,77 @@ static const CopyToRoutine CopyToRoutineCSV = {
...
 /* Implementation of the start callback for text and CSV formats */
 static void
-CopyToTextLikeStart(CopyToState cstate, TupleDesc tupDesc)
+CopyToTextLikeStart(CopyToState ccstate, TupleDesc tupDesc)
 {
+	CopyToStateTextLike *cstate = (CopyToStateTextLike *) ccstate;

How about always using "cstate" for "CopyToState"? In other
functions in this patch, "CopyToState" is referred "cstate"
or "cctate".

We can use "state" or something for
"CopyToStateTextLike". (0002 uses "state" for
"CopyFromStateBuiltins".)

+		cstate->base.opts.null_print_client = pg_server_to_any(cstate->base.opts.null_print,
+															   cstate->base.opts.null_print_len,
+															   cstate->file_encoding);

We can use "ccstate->" instead of "cstate->base." in this
function.

@@ -614,6 +603,54 @@ EndCopy(CopyToState cstate)
 	pfree(cstate);
 }
 
+/*
+ * Allocate COPY TO state data based on the format's EsimateStateSpace
+ * callback.
+ */
+static CopyToState
+create_copyto_state(ParseState *pstate, List *options)

"Esimate" ->
"Estimate"

How about using CamelCase like "CreateCopyToState" for
function name like other functions in this file?

+	Size		req_size;

"state_size" may be better.

@@ -1233,16 +1246,16 @@ CopyOneRowTo(CopyToState cstate, TupleTableSlot *slot)
...
 static void
-CopyAttributeOutText(CopyToState cstate, const char *string)
+CopyAttributeOutText(CopyToStateTextLike * cstate, const char *string)
 {

CopyAttributeOutText(CopyToState cstate, const char *string)
{
	CopyToStateTextLike *state = (CopyToStateTextLike *)cstate;

may reduce "cstate->base." and "(CopyToState) cstate" in
this function.

BTW, could you remove a needless space after "*" in
"CopyToStateTextLike * cstate"?

0002:

diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index 12781963b4f..0c51e5ba5e1 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -129,6 +131,7 @@ static void CopyFromBinaryEnd(CopyFromState cstate);
 
 /* text format */
 static const CopyFromRoutine CopyFromRoutineText = {
+	.CopyFromEstimateStateSpace = CopyFromBuiltinsEstimateSpace,

How about including "State"
("CopyFromBuiltinsEstimateStateSpace")?

@@ -145,54 +149,129 @@ static const CopyFromRoutine CopyFromRoutineCSV = {
...
+/*
+ * Common routine to initialize CopyFromStateBuiltins data.
+ */
+static void
+initialize_copyfrom_bultins_state(CopyFromStateBuiltins * state, TupleDesc tupDesc)

* How about using CamelCase like other functions in this file?
* How about using the same name as the struct?

InitializeCopyFromStateBuiltins?

@@ -1379,8 +1462,8 @@ CopyFrom(CopyFromState cstate)
 					/* Add this tuple to the tuple buffer */
 					CopyMultiInsertInfoStore(&multiInsertInfo,
 											 resultRelInfo, myslot,
-											 cstate->line_buf.len,
-											 cstate->cur_lineno);
+											 rowinfo.tuplen,
+											 rowinfo.lineno);

How about passing "CopyFromRowInfo *" instead of
"rowinfo.tuplen" and "rowinfo.lineno"?

@@ -1512,6 +1595,50 @@ CopyFrom(CopyFromState cstate)
 	return processed;
 }
 
+static CopyFromState
+create_copyfrom_state(ParseState *pstate, List *options)

How about using CamelCase like other functions in this file?

CreateCopyFromState?

@@ -1138,19 +1156,29 @@ CopyFromBinaryOneRow(CopyFromState cstate, ExprContext *econtext, Datum *values,
...
+	if (rowinfo)
+	{
+		/*
+		 * XXX: We used to use line_buf.len but we don't actually use line_buf
+		 * in binary format.
+		 */
+		rowinfo->lineno = cstate->base.cur_lineno;
+		rowinfo->tuplen = cstate->line_buf.len;
 	}

How about always setting "0" to "rowinfo->tuplen" instead of
using "cstate->line_buf.len"?

diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index d75a70715a4..30a1d2bff6e 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -48,6 +48,12 @@ typedef enum CopyLogVerbosityChoice
...
+typedef struct CopyFromRowInfo
+{
+	uint64		lineno;
+	int			tuplen;
+}			CopyFromRowInfo;

I don't have a strong opinion nor alternative but I'm not
sure whether this name is suitable or not...

diff --git a/src/include/commands/copyapi.h b/src/include/commands/copyapi.h
index 3b9982d54b8..c3d2199a0b6 100644
--- a/src/include/commands/copyapi.h
+++ b/src/include/commands/copyapi.h
@@ -99,12 +104,11 @@ typedef struct CopyFromRoutine
 	 * Returns false if there are no more tuples to read.
 	 */
 	bool		(*CopyFromOneRow) (CopyFromState cstate, ExprContext *econtext,
-								   Datum *values, bool *nulls);
+								   Datum *values, bool *nulls, CopyFromRowInfo * rowinfo);

Can we add some docstrings for "rowinfo"?

diff --git a/src/include/commands/copystate.h b/src/include/commands/copystate.h
index 7561083a323..145dccd0f8f 100644
--- a/src/include/commands/copystate.h
+++ b/src/include/commands/copystate.h
@@ -65,4 +67,99 @@ typedef struct CopyToStateData
...
+/*
+ * Represents the different source cases we need to worry about at
+ * the bottom level
+ */
+typedef enum CopySource
+{
+	COPY_FILE,					/* from file (or a piped program) */
+	COPY_FRONTEND,				/* from frontend */
+	COPY_CALLBACK,				/* from callback function */
+} CopySource;

Can we use "COPY_SOURCE_" prefix instead of "COPY_" prefix
such as "COPY_SOURCE_FILE"?

0003:

diff --git a/src/backend/commands/copy_custom_format.c b/src/backend/commands/copy_custom_format.c
new file mode 100644
index 00000000000..8bef6e779ac
--- /dev/null
+++ b/src/backend/commands/copy_custom_format.c

+/*
+ * Returns true if the given custom format name is registered.
+ */
+bool
+FindCustomCopyFormat(const char *fmt_name)
+{
+	for (int i = 0; i < CopyCustomFormatAssigned; i++)
+	{
+		if (strcmp(CopyCustomFormatArray[i].fmt_name, fmt_name) == 0)
+			return true;
+	}
+
+	return false;
+}

How about using other word than "Find" here? I expect that
"FindXXX()" returns a found value instead of "whether found
or not" as bool.

CustomCopyFormatExists()?

+bool
+GetCustomCopyToRoutine(const char *fmt_name, const CopyToRoutine **to_routine)
+{
+	for (int i = 0; i < CopyCustomFormatAssigned; i++)
+	{
+		if (strcmp(CopyCustomFormatArray[i].fmt_name, fmt_name) == 0)
+		{
+			*to_routine = CopyCustomFormatArray[i].to_routine;
+			return true;
+		}
+	}
+
+	return false;
+}

How about returning "const CopyToRoutine *" instead of
"bool"? We can use "FindCustomCopyFormat()" whether the
given format name exists or not.

+bool
+GetCustomCopyFromRoutine(const char *fmt_name, const CopyFromRoutine **from_routine)

Ditto.

diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index 30a1d2bff6e..82f07b05823 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -120,6 +120,12 @@ extern uint64 CopyFrom(CopyFromState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ProcessCopyBuiltinOptions(List *options, CopyFormatOptions *opts_out,
+									  bool is_from, List **other_options, ParseState *pstate);

It seems that this change should exist in 0004.

0004:

diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index b1b3ae141eb..ea31fa911f9 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -1570,3 +1571,32 @@ CreateCopyDestReceiver(void)
 
 	return (DestReceiver *) self;
 }
+
+static void
+ProcessCopyToOptions(CopyToState cstate, List *options, ParseState *pstate)
+{
+	bool		temp_state = false;
+	List	   *other_options = NIL;
+	CopyFormatOptions *opts;
+
+	if (cstate == NULL)
+	{
+		cstate = create_copyto_state(pstate, options);
+		temp_state = true;
+	}
+
+	opts = &cstate->opts;
+
+	ProcessCopyBuiltinOptions(options, opts, false, &other_options, pstate);
+
+	foreach_node(DefElem, option, options)

options ->
other_options

(This change exists in 0005.)

0006:

diff --git a/src/test/modules/test_copy_custom_format/test_copy_custom_format.c b/src/test/modules/test_copy_custom_format/test_copy_custom_format.c
new file mode 100644
index 00000000000..a63390e875b
--- /dev/null
+++ b/src/test/modules/test_copy_custom_format/test_copy_custom_format.c

+static Size
+TestCopyToEsimateSpace(void)
+{
+	return sizeof(TestCopyToState);
+}
+
+static Size
+TestCopyFromEsimateSpace(void)
+{
+	return sizeof(TestCopyFromState);
+}

EsimateSpace ->
EstimateStateSpace

+	if (strcmp(option->defname, "common_int") == 0)
+	{
+		int			val = defGetInt32(option);
+
+		opt->common_int = val;
+
+		return true;
+	}
+	else if (strcmp(option->defname, "common_bool") == 0)
+	{
+		bool		val = defGetBoolean(option);
+
+		opt->common_bool = val;
+
+		return true;

We may not need to use local variables:

opt->common_int = defGetInt32(option);
opt->common_bool = defGetBoolean(option);

> reading all data to access the metadata.

This is outside the scope of this patch but I've created
a custom COPY format implementation for Apache Parquet:
https://github.com/kou/pg-copy-parquet

We need to start parsing from footer as mentioned above. So
the implementation reads all data before it starts parsing:

https://github.com/kou/pg-copy-parquet/blob/7da367ea81d8964f5045fe0b1514a798d4ecbbc7/copy_parquet.cc#L410-L434

If we have random access API, we don't need to read all
data. It improves performance.

Anyway, this is outside the scope of this patch. We can
discuss this in a separated thread after we merge this
patch.

Thanks,
-- 
kou

---

From: Tomas Vondra <[email-masked]>
Date: Mon, 17 Nov 2025 18:04:46 +0100

> to verify there are no performance regressions.

I got pinged about this patch off-list. I won't have capacity to do a
proper review, anytime soon, but I got a bit of time to do a simple
benchmark (which seems useful as that was one of the concerns in this
thread, it seems).

Attached is a script that does COPY TO/FROM with the built-in formats,
on table with 1, 10 and 100 integer columns. The data sets are between
10 and 1M rows. The table is UNLOGGED, to eliminate WAL overhead.

The attached PDF summarizes results from my ryzen machine, for master
and patched build. The final columns are comparison (i.e. copy/master)
of the timings. Values >100% are regressions (marked as red).

It seems quite "red", but it's not particularly conclusive. The
differences are mostly within 5%, and that could be caused e.g. by
changes to binary layout. And some of the cases got faster too.

It might be interesting to get results from other machines. The script
may need some adjustments, but it should be too difficult.

The other thing Andres was concerned about is "the amount of COPY
performance improvements it forecloses". I have no opinion on that, as
it depends on what improvements Andres envisioned.

regards

-- 
Tomas Vondra

---

From: Sutou Kouhei <[email-masked]>
Date: Tue, 02 Dec 2025 11:39:57 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Mon, 17 Nov 2025 18:04:46 +0100,

> benchmark (which seems useful as that was one of the concerns in this

Thanks!!!

I also do the same condition benchmark on my Mac mini:

Machine:

* Apple M1 (8 core)
* Memory: 16GB
* macOS Sequoia (15.6)

Parameters:

* N integer columns: 1 10 100
* N rows: 10 100 1000 10000 10000 100000 1000000
* Formats: text csv binary
* Operations: FROM TO
* Patches: 0001 0002 0003 0004 0005 0006

I ran 5 times for each parameter set and choose the median
elapsed time.

I used
https://gitlab.com/ktou/pg-bench/-/blob/main/copy-format-extendable/run.sh
. I attach it.

I measured 6 times. See the attached mac-mini-result-${N}.{csv,pdf}.

A PDF has 3 columns. They are text, csv and binary formats
from left to right.

1st row uses COPY FROM and 0001 patch.
2nd row uses COPY TO and 0001 patch.

3rd row uses COPY FROM and 0002 patch.
4th row uses COPY TO and 0002 patch.

...

Each heatmap visualizes (${elapsed_time_patch} /
${elapsed_time_master}) * 100. 100 > (red) means slower and
100 < (blue) means faster.

It seems that they don't show any reproducible trends.

For example, the binary cases in mac-mini-result-2.pdf show
that patched cases are always slower but the binary cases in
mac-mini-result-{1,6}.pdf show that most patched cases are
faster. The binary cases in mac-mini-result-{1,5,6}.pdf show
that 0006 patch is slower than 0005 patch but the binary
cases in mac-mini-result-{3,4}.pdf don't show it.

Another example, the text cases in mac-mini-result-1.pdf
show that patched cases are always slower but the text cases
in mac-mini-result-1.pdf show that most patched cases are
faster.

I hope that these numbers help to proceed this proposal.

Thanks,
-- 
kou
#!/bin/bash
# -*- sh-indentation: 2; sh-basic-offset: 2-*-

# This is based on codes from Michael Paquier and Tomas Vondra:
# * https://www.postgresql.org/message-id/flat/Zbr6piWuVHDtFFOl%40paquier.xyz#dbbec4d5c54ef2317be01a54abaf495c
# * https://www.postgresql.org/message-id/flat/26541788-8853-4d93-86cd-5f701b13ae51%40enterprisedb.com

DIR=${1:-$(pwd)}

psql postgres > /dev/null 2>&1 <<EOF
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
EOF
psql test > /dev/null 2>&1 <<EOF
CREATE EXTENSION blackhole_am;
CREATE OR REPLACE FUNCTION create_table_cols(tabname text, num_cols int)
RETURNS VOID AS
\$func\$
DECLARE
  query text;
BEGIN
  query := 'CREATE UNLOGGED TABLE ' || tabname || ' (';
  FOR i IN 1..num_cols LOOP
    query := query || 'a_' || i::text || ' int2 default 1';
    IF i != num_cols THEN
      query := query || ', ';
    END IF;
  END LOOP;
  query := query || ')';
  EXECUTE format(query);
END
\$func\$ LANGUAGE plpgsql;
EOF

for format in text csv binary; do
  for n_columns in 1 10 100; do
    for n_rows in 10 100 1000 10000 10000 100000 1000000; do
      psql test > /dev/null 2>&1 <<EOF
DROP TABLE IF EXISTS to_table;
DROP TABLE IF EXISTS from_table;

SELECT create_table_cols ('to_table', ${n_columns});
SELECT create_table_cols ('from_table', ${n_columns});

INSERT INTO to_table SELECT 1 FROM generate_series(1, ${n_rows});

COPY to_table TO '$DIR/test.data' WITH (FORMAT ${format});

ALTER TABLE from_table SET ACCESS METHOD blackhole_am;
EOF

      # run COPY TO 5x
      for r in $(seq 1 5); do
        s=$(psql test -t -A -c "SELECT EXTRACT(EPOCH FROM now())")
        psql test -c "COPY to_table TO '/dev/null' WITH (FORMAT ${format})" > /dev/null 2>&1
        d=$(psql test -t -A -c "SELECT 1000 * (EXTRACT(EPOCH FROM now()) - $s)")
        echo "TO,${format},${n_columns},${n_rows},${r},${d}"
      done

      # run COPY FROM 5x
      for r in $(seq 1 5); do
        s=$(psql test -t -A -c "SELECT EXTRACT(EPOCH FROM now())")
        psql test -c "COPY from_table FROM '$DIR/test.data' WITH (FORMAT ${format})" > /dev/null 2>&1
        d=$(psql test -t -A -c "SELECT 1000 * (EXTRACT(EPOCH FROM now()) - $s)")
        echo "FROM,${format},${n_columns},${n_rows},${r},${d}"
      done
    done
  done
done
version,type,format,n_columns,n_rows,runtime,base_runtime,diff_runtime,diff_percentage
0,FROM,binary,1,10,13.383000373840332,13.383000373840332,0.0,100.0
1,FROM,binary,1,10,13.312999725341797,13.383000373840332,-0.07000064849853516,99.47694396972656
2,FROM,binary,1,10,13.267000198364258,13.383000373840332,-0.11600017547607422,99.13323211669922
3,FROM,binary,1,10,13.321999549865723,13.383000373840332,-0.061000823974609375,99.544189453125
4,FROM,binary,1,10,13.362000465393066,13.383000373840332,-0.020999908447265625,99.84308624267578
5,FROM,binary,1,10,13.406999588012695,13.383000373840332,0.02399921417236328,100.17932891845703
6,FROM,binary,1,10,13.329999923706055,13.383000373840332,-0.053000450134277344,99.60397338867188
0,TO,binary,1,10,13.076000213623047,13.076000213623047,0.0,100.0
1,TO,binary,1,10,13.147000312805176,13.076000213623047,0.0710000991821289,100.54297637939453
2,TO,binary,1,10,13.01099967956543,13.076000213623047,-0.06500053405761719,99.5029067993164
3,TO,binary,1,10,13.026000022888184,13.076000213623047,-0.05000019073486328,99.61761474609375
4,TO,binary,1,10,13.083999633789062,13.076000213623047,0.007999420166015625,100.0611801147461
5,TO,binary,1,10,13.111000061035156,13.076000213623047,0.034999847412109375,100.26766204833984
6,TO,binary,1,10,13.092000007629395,13.076000213623047,0.015999794006347656,100.12236022949219
0,FROM,binary,1,100,13.413999557495117,13.413999557495117,0.0,100.0
1,FROM,binary,1,100,13.491999626159668,13.413999557495117,0.07800006866455078,100.58148193359375
2,FROM,binary,1,100,13.395999908447266,13.413999557495117,-0.017999649047851562,99.86581420898438
3,FROM,binary,1,100,13.4350004196167,13.413999557495117,0.02100086212158203,100.15655517578125
4,FROM,binary,1,100,13.531999588012695,13.413999557495117,0.11800003051757812,100.87968444824219
5,FROM,binary,1,100,13.420999526977539,13.413999557495117,0.006999969482421875,100.05219268798828
6,FROM,binary,1,100,13.503000259399414,13.413999557495117,0.08900070190429688,100.66349792480469
0,TO,binary,1,100,13.112000465393066,13.112000465393066,0.0,100.0
1,TO,binary,1,100,13.105999946594238,13.112000465393066,-0.006000518798828125,99.95423889160156
2,TO,binary,1,100,13.21500015258789,13.112000465393066,0.10299968719482422,100.78553771972656
3,TO,binary,1,100,13.142000198364258,13.112000465393066,0.029999732971191406,100.22879791259766
4,TO,binary,1,100,13.071999549865723,13.112000465393066,-0.04000091552734375,99.69493103027344
5,TO,binary,1,100,13.013999938964844,13.112000465393066,-0.09800052642822266,99.2525863647461
6,TO,binary,1,100,13.083999633789062,13.112000465393066,-0.028000831604003906,99.78644561767578
0,FROM,binary,1,1000,15.484999656677246,15.484999656677246,0.0,100.0
1,FROM,binary,1,1000,15.571000099182129,15.484999656677246,0.08600044250488281,100.55538177490234
2,FROM,binary,1,1000,15.420000076293945,15.484999656677246,-0.06499958038330078,99.58023834228516
3,FROM,binary,1,1000,15.333999633789062,15.484999656677246,-0.1510000228881836,99.02486419677734
4,FROM,binary,1,1000,15.522000312805176,15.484999656677246,0.03700065612792969,100.23894500732422
5,FROM,binary,1,1000,15.440999984741211,15.484999656677246,-0.043999671936035156,99.71585845947266
6,FROM,binary,1,1000,15.571000099182129,15.484999656677246,0.08600044250488281,100.55538177490234
0,TO,binary,1,1000,13.156999588012695,13.156999588012695,0.0,100.0
1,TO,binary,1,1000,13.185999870300293,13.156999588012695,0.029000282287597656,100.22042083740234
2,TO,binary,1,1000,13.093000411987305,13.156999588012695,-0.06399917602539062,99.5135726928711
3,TO,binary,1,1000,13.15999984741211,13.156999588012695,0.0030002593994140625,100.0228042602539
4,TO,binary,1,1000,13.152999877929688,13.156999588012695,-0.0039997100830078125,99.9696044921875
5,TO,binary,1,1000,13.048999786376953,13.156999588012695,-0.10799980163574219,99.17914581298828
6,TO,binary,1,1000,13.14900016784668,13.156999588012695,-0.007999420166015625,99.93919372558594
0,FROM,binary,1,10000,16.064498901367188,16.064498901367188,0.0,100.0
1,FROM,binary,1,10000,15.933500289916992,16.064498901367188,-0.1309986114501953,99.1845474243164
2,FROM,binary,1,10000,15.858999252319336,16.064498901367188,-0.20549964904785156,98.72077941894531
3,FROM,binary,1,10000,15.935500144958496,16.064498901367188,-0.1289987564086914,99.19699096679688
4,FROM,binary,1,10000,15.975500106811523,16.064498901367188,-0.08899879455566406,99.44599151611328
5,FROM,binary,1,10000,15.803500175476074,16.064498901367188,-0.2609987258911133,98.37530517578125
6,FROM,binary,1,10000,16.045000076293945,16.064498901367188,-0.019498825073242188,99.87862396240234
0,TO,binary,1,10000,14.01300048828125,14.01300048828125,0.0,100.0
1,TO,binary,1,10000,14.031999588012695,14.01300048828125,0.018999099731445312,100.13557434082031
2,TO,binary,1,10000,13.94849967956543,14.01300048828125,-0.06450080871582031,99.53971099853516
3,TO,binary,1,10000,13.990499496459961,14.01300048828125,-0.022500991821289062,99.83942413330078
4,TO,binary,1,10000,13.998499870300293,14.01300048828125,-0.014500617980957031,99.89652252197266
5,TO,binary,1,10000,13.931499481201172,14.01300048828125,-0.08150100708007812,99.41838836669922
6,TO,binary,1,10000,14.052499771118164,14.01300048828125,0.03949928283691406,100.28186798095703
0,FROM,binary,1,100000,20.371000289916992,20.371000289916992,0.0,100.0
1,FROM,binary,1,100000,20.628000259399414,20.371000289916992,0.2569999694824219,101.26158905029297
2,FROM,binary,1,100000,20.312000274658203,20.371000289916992,-0.05900001525878906,99.71037292480469
3,FROM,binary,1,100000,20.461000442504883,20.371000289916992,0.09000015258789062,100.44180297851562
4,FROM,binary,1,100000,20.364999771118164,20.371000289916992,-0.006000518798828125,99.97054290771484
5,FROM,binary,1,100000,20.173999786376953,20.371000289916992,-0.19700050354003906,99.0329360961914
6,FROM,binary,1,100000,20.312999725341797,20.371000289916992,-0.05800056457519531,99.71527862548828
0,TO,binary,1,100000,22.19499969482422,22.19499969482422,0.0,100.0
1,TO,binary,1,100000,22.172000885009766,22.19499969482422,-0.022998809814453125,99.89637756347656
2,TO,binary,1,100000,22.048999786376953,22.19499969482422,-0.14599990844726562,99.34219360351562
3,TO,binary,1,100000,22.06599998474121,22.19499969482422,-0.1289997100830078,99.41879272460938
4,TO,binary,1,100000,22.309999465942383,22.19499969482422,0.11499977111816406,100.51812744140625
5,TO,binary,1,100000,22.010000228881836,22.19499969482422,-0.1849994659423828,99.1664810180664
6,TO,binary,1,100000,22.12299919128418,22.19499969482422,-0.07200050354003906,99.67559814453125
0,FROM,binary,1,1000000,64.94200134277344,64.94200134277344,0.0,100.0
1,FROM,binary,1,1000000,66.81800079345703,64.94200134277344,1.8759994506835938,102.88872528076172
2,FROM,binary,1,1000000,64.05799865722656,64.94200134277344,-0.884002685546875,98.63877868652344
3,FROM,binary,1,1000000,65.34300231933594,64.94200134277344,0.4010009765625,100.61747741699219
4,FROM,binary,1,1000000,64.34300231933594,64.94200134277344,-0.5989990234375,99.07764434814453
5,FROM,binary,1,1000000,63.73899841308594,64.94200134277344,-1.2030029296875,98.14756774902344
6,FROM,binary,1,1000000,63.62300109863281,64.94200134277344,-1.319000244140625,97.96895599365234
0,TO,binary,1,1000000,100.69999694824219,100.69999694824219,0.0,100.0
1,TO,binary,1,1000000,100.81300354003906,100.69999694824219,0.113006591796875,100.11222076416016
2,TO,binary,1,1000000,100.9489974975586,100.69999694824219,0.24900054931640625,100.24726104736328
3,TO,binary,1,1000000,100.76499938964844,100.69999694824219,0.06500244140625,100.0645523071289
4,TO,binary,1,1000000,101.25399780273438,100.69999694824219,0.5540008544921875,100.5501480102539
5,TO,binary,1,1000000,100.94400024414062,100.69999694824219,0.2440032958984375,100.24230194091797
6,TO,binary,1,1000000,101.94999694824219,100.69999694824219,1.25,101.24131774902344
0,FROM,binary,10,10,13.397000312805176,13.397000312805176,0.0,100.0
1,FROM,binary,10,10,13.32800006866455,13.397000312805176,-0.069000244140625,99.48495483398438
2,FROM,binary,10,10,13.303000450134277,13.397000312805176,-0.09399986267089844,99.29835510253906
3,FROM,binary,10,10,13.324000358581543,13.397000312805176,-0.07299995422363281,99.4551010131836
4,FROM,binary,10,10,13.369999885559082,13.397000312805176,-0.02700042724609375,99.7984619140625
5,FROM,binary,10,10,13.24899959564209,13.397000312805176,-0.14800071716308594,98.89527130126953
6,FROM,binary,10,10,13.355999946594238,13.397000312805176,-0.0410003662109375,99.69396209716797
0,TO,binary,10,10,13.097000122070312,13.097000122070312,0.0,100.0
1,TO,binary,10,10,13.104000091552734,13.097000122070312,0.006999969482421875,100.0534439086914
2,TO,binary,10,10,13.050999641418457,13.097000122070312,-0.04600048065185547,99.64877319335938
3,TO,binary,10,10,12.99899959564209,13.097000122070312,-0.09800052642822266,99.2517318725586
4,TO,binary,10,10,13.128000259399414,13.097000122070312,0.031000137329101562,100.23670196533203
5,TO,binary,10,10,12.961000442504883,13.097000122070312,-0.1359996795654297,98.96160125732422
6,TO,binary,10,10,13.194999694824219,13.097000122070312,0.09799957275390625,100.7482681274414
0,FROM,binary,10,100,13.628999710083008,13.628999710083008,0.0,100.0
1,FROM,binary,10,100,13.460000038146973,13.628999710083008,-0.16899967193603516,98.75999450683594
2,FROM,binary,10,100,13.42300033569336,13.628999710083008,-0.20599937438964844,98.488525390625
3,FROM,binary,10,100,13.472999572753906,13.628999710083008,-0.15600013732910156,98.85538482666016
4,FROM,binary,10,100,13.4350004196167,13.628999710083008,-0.1939992904663086,98.57656860351562
5,FROM,binary,10,100,13.458999633789062,13.628999710083008,-0.1700000762939453,98.7526626586914
6,FROM,binary,10,100,13.597999572753906,13.628999710083008,-0.031000137329101562,99.77254486083984
0,TO,binary,10,100,13.116999626159668,13.116999626159668,0.0,100.0
1,TO,binary,10,100,13.114999771118164,13.116999626159668,-0.0019998550415039062,99.98475646972656
2,TO,binary,10,100,13.031999588012695,13.116999626159668,-0.08500003814697266,99.35198211669922
3,TO,binary,10,100,13.069000244140625,13.116999626159668,-0.04799938201904297,99.63407135009766
4,TO,binary,10,100,13.13599967956543,13.116999626159668,0.01900005340576172,100.14485168457031
5,TO,binary,10,100,13.060999870300293,13.116999626159668,-0.055999755859375,99.57307434082031
6,TO,binary,10,100,13.166000366210938,13.116999626159668,0.04900074005126953,100.37356567382812
0,FROM,binary,10,1000,15.838000297546387,15.838000297546387,0.0,100.0
1,FROM,binary,10,1000,15.732000350952148,15.838000297546387,-0.10599994659423828,99.33072662353516
2,FROM,binary,10,1000,15.616999626159668,15.838000297546387,-0.22100067138671875,98.60462188720703
3,FROM,binary,10,1000,15.576000213623047,15.838000297546387,-0.26200008392333984,98.34574890136719
4,FROM,binary,10,1000,15.687000274658203,15.838000297546387,-0.1510000228881836,99.04659271240234
5,FROM,binary,10,1000,15.512999534606934,15.838000297546387,-0.3250007629394531,97.94796752929688
6,FROM,binary,10,1000,15.623000144958496,15.838000297546387,-0.21500015258789062,98.64250183105469
0,TO,binary,10,1000,13.567000389099121,13.567000389099121,0.0,100.0
1,TO,binary,10,1000,13.425999641418457,13.567000389099121,-0.14100074768066406,98.96070861816406
2,TO,binary,10,1000,13.401000022888184,13.567000389099121,-0.1660003662109375,98.77644348144531
3,TO,binary,10,1000,13.270999908447266,13.567000389099121,-0.29600048065185547,97.81822967529297
4,TO,binary,10,1000,13.41100025177002,13.567000389099121,-0.15600013732910156,98.85015106201172
5,TO,binary,10,1000,13.267999649047852,13.567000389099121,-0.29900074005126953,97.7961196899414
6,TO,binary,10,1000,13.397000312805176,13.567000389099121,-0.1700000762939453,98.74696350097656
0,FROM,binary,10,10000,17.310501098632812,17.310501098632812,0.0,100.0
1,FROM,binary,10,10000,17.279499053955078,17.310501098632812,-0.031002044677734375,99.82090759277344
2,FROM,binary,10,10000,17.172000885009766,17.310501098632812,-0.13850021362304688,99.19990539550781
3,FROM,binary,10,10000,17.14350128173828,17.310501098632812,-0.16699981689453125,99.03527069091797
4,FROM,binary,10,10000,17.27199935913086,17.310501098632812,-0.038501739501953125,99.77758026123047
5,FROM,binary,10,10000,17.194499969482422,17.310501098632812,-0.11600112915039062,99.32987976074219
6,FROM,binary,10,10000,17.27750015258789,17.310501098632812,-0.033000946044921875,99.80935668945312
0,TO,binary,10,10000,16.21500015258789,16.21500015258789,0.0,100.0
1,TO,binary,10,10000,16.238500595092773,16.21500015258789,0.023500442504882812,100.14493560791016
2,TO,binary,10,10000,16.139999389648438,16.21500015258789,-0.07500076293945312,99.53746032714844
3,TO,binary,10,10000,16.17599868774414,16.21500015258789,-0.03900146484375,99.75946807861328
4,TO,binary,10,10000,16.263500213623047,16.21500015258789,0.04850006103515625,100.29911041259766
5,TO,binary,10,10000,16.20199966430664,16.21500015258789,-0.01300048828125,99.9198226928711
6,TO,binary,10,10000,16.300498962402344,16.21500015258789,0.08549880981445312,100.52728271484375
0,FROM,binary,10,100000,33.16600036621094,33.16600036621094,0.0,100.0
1,FROM,binary,10,100000,34.119998931884766,33.16600036621094,0.9539985656738281,102.87643432617188
2,FROM,binary,10,100000,32.76300048828125,33.16600036621094,-0.4029998779296875,98.78489685058594
3,FROM,binary,10,100000,33.03300094604492,33.16600036621094,-0.13299942016601562,99.59898376464844
4,FROM,binary,10,100000,32.98699951171875,33.16600036621094,-0.1790008544921875,99.46028900146484
5,FROM,binary,10,100000,32.92100143432617,33.16600036621094,-0.24499893188476562,99.26129913330078
6,FROM,binary,10,100000,33.02899932861328,33.16600036621094,-0.13700103759765625,99.58692169189453
0,TO,binary,10,100000,44.52000045776367,44.52000045776367,0.0,100.0
1,TO,binary,10,100000,44.39099884033203,44.52000045776367,-0.12900161743164062,99.71023559570312
2,TO,binary,10,100000,44.38999938964844,44.52000045776367,-0.13000106811523438,99.70800018310547
3,TO,binary,10,100000,44.31800079345703,44.52000045776367,-0.20199966430664062,99.54627227783203
4,TO,binary,10,100000,44.47600173950195,44.52000045776367,-0.04399871826171875,99.90116882324219
5,TO,binary,10,100000,44.88399887084961,44.52000045776367,0.3639984130859375,100.81761169433594
6,TO,binary,10,100000,44.89500045776367,44.52000045776367,0.375,100.84232330322266
0,FROM,binary,10,1000000,187.33299255371094,187.33299255371094,0.0,100.0
1,FROM,binary,10,1000000,197.53799438476562,187.33299255371094,10.205001831054688,105.44751739501953
2,FROM,binary,10,1000000,186.9199981689453,187.33299255371094,-0.412994384765625,99.779541015625
3,FROM,binary,10,1000000,187.60699462890625,187.33299255371094,0.2740020751953125,100.14627075195312
4,FROM,binary,10,1000000,187.51199340820312,187.33299255371094,0.1790008544921875,100.0955581665039
5,FROM,binary,10,1000000,187.42999267578125,187.33299255371094,0.0970001220703125,100.05178833007812
6,FROM,binary,10,1000000,187.27099609375,187.33299255371094,-0.0619964599609375,99.96690368652344
0,TO,binary,10,1000000,321.8659973144531,321.8659973144531,0.0,100.0
1,TO,binary,10,1000000,322.02398681640625,321.8659973144531,0.157989501953125,100.04908752441406
2,TO,binary,10,1000000,321.7799987792969,321.8659973144531,-0.08599853515625,99.97328186035156
3,TO,binary,10,1000000,321.7929992675781,321.8659973144531,-0.072998046875,99.9773178100586
4,TO,binary,10,1000000,322.9670104980469,321.8659973144531,1.10101318359375,100.34207153320312
5,TO,binary,10,1000000,331.0870056152344,321.8659973144531,9.22100830078125,102.86486053466797
6,TO,binary,10,1000000,328.6780090332031,321.8659973144531,6.81201171875,102.11641693115234
0,FROM,binary,100,10,13.640999794006348,13.640999794006348,0.0,100.0
1,FROM,binary,100,10,13.487000465393066,13.640999794006348,-0.15399932861328125,98.87105560302734
2,FROM,binary,100,10,13.482999801635742,13.640999794006348,-0.15799999237060547,98.84172821044922
3,FROM,binary,100,10,13.442999839782715,13.640999794006348,-0.1979999542236328,98.54849243164062
4,FROM,binary,100,10,13.418000221252441,13.640999794006348,-0.22299957275390625,98.36522674560547
5,FROM,binary,100,10,13.42199993133545,13.640999794006348,-0.21899986267089844,98.39454650878906
6,FROM,binary,100,10,13.428000450134277,13.640999794006348,-0.2129993438720703,98.43853759765625
0,TO,binary,100,10,13.293999671936035,13.293999671936035,0.0,100.0
1,TO,binary,100,10,13.142999649047852,13.293999671936035,-0.1510000228881836,98.86415100097656
2,TO,binary,100,10,13.243000030517578,13.293999671936035,-0.05099964141845703,99.61637115478516
3,TO,binary,100,10,13.154000282287598,13.293999671936035,-0.1399993896484375,98.9468994140625
4,TO,binary,100,10,13.227999687194824,13.293999671936035,-0.06599998474121094,99.50353240966797
5,TO,binary,100,10,13.105999946594238,13.293999671936035,-0.18799972534179688,98.58583068847656
6,TO,binary,100,10,13.196999549865723,13.293999671936035,-0.0970001220703125,99.27033996582031
0,FROM,binary,100,100,13.78600025177002,13.78600025177002,0.0,100.0
1,FROM,binary,100,100,13.659000396728516,13.78600025177002,-0.1269998550415039,99.07877349853516
2,FROM,binary,100,100,13.67300033569336,13.78600025177002,-0.11299991607666016,99.18032836914062
3,FROM,binary,100,100,13.678000450134277,13.78600025177002,-0.10799980163574219,99.21659851074219
4,FROM,binary,100,100,13.675000190734863,13.78600025177002,-0.11100006103515625,99.19483947753906
5,FROM,binary,100,100,13.602999687194824,13.78600025177002,-0.1830005645751953,98.67256164550781
6,FROM,binary,100,100,13.770999908447266,13.78600025177002,-0.015000343322753906,99.89118957519531
0,TO,binary,100,100,13.413000106811523,13.413000106811523,0.0,100.0
1,TO,binary,100,100,13.345000267028809,13.413000106811523,-0.06799983978271484,99.49303436279297
2,TO,binary,100,100,13.336000442504883,13.413000106811523,-0.07699966430664062,99.4259262084961
3,TO,binary,100,100,13.369000434875488,13.413000106811523,-0.043999671936035156,99.67195892333984
4,TO,binary,100,100,13.385000228881836,13.413000106811523,-0.0279998779296875,99.79124450683594
5,TO,binary,100,100,13.460000038146973,13.413000106811523,0.04699993133544922,100.35040283203125
6,TO,binary,100,100,13.90999984741211,13.413000106811523,0.49699974060058594,103.70536041259766
0,FROM,binary,100,1000,17.26099967956543,17.26099967956543,0.0,100.0
1,FROM,binary,100,1000,17.426000595092773,17.26099967956543,0.16500091552734375,100.95591735839844
2,FROM,binary,100,1000,17.37700080871582,17.26099967956543,0.11600112915039062,100.67204284667969
3,FROM,binary,100,1000,17.408000946044922,17.26099967956543,0.1470012664794922,100.85164642333984
4,FROM,binary,100,1000,17.402000427246094,17.26099967956543,0.14100074768066406,100.8168716430664
5,FROM,binary,100,1000,17.224000930786133,17.26099967956543,-0.036998748779296875,99.78565216064453
6,FROM,binary,100,1000,18.3439998626709,17.26099967956543,1.0830001831054688,106.27426147460938
0,TO,binary,100,1000,15.418000221252441,15.418000221252441,0.0,100.0
1,TO,binary,100,1000,15.38700008392334,15.418000221252441,-0.031000137329101562,99.79893493652344
2,TO,binary,100,1000,15.401000022888184,15.418000221252441,-0.017000198364257812,99.88973999023438
3,TO,binary,100,1000,15.444999694824219,15.418000221252441,0.026999473571777344,100.17511749267578
4,TO,binary,100,1000,15.425999641418457,15.418000221252441,0.007999420166015625,100.0518798828125
5,TO,binary,100,1000,15.380000114440918,15.418000221252441,-0.03800010681152344,99.75353240966797
6,TO,binary,100,1000,17.35099983215332,15.418000221252441,1.932999610900879,112.53729248046875
0,FROM,binary,100,10000,30.20949935913086,30.20949935913086,0.0,100.0
1,FROM,binary,100,10000,31.256999969482422,30.20949935913086,1.0475006103515625,103.46745300292969
2,FROM,binary,100,10000,29.991500854492188,30.20949935913086,-0.21799850463867188,99.27838134765625
3,FROM,binary,100,10000,30.010000228881836,30.20949935913086,-0.19949913024902344,99.33961486816406
4,FROM,binary,100,10000,30.04199981689453,30.20949935913086,-0.16749954223632812,99.44554138183594
5,FROM,binary,100,10000,29.998001098632812,30.20949935913086,-0.21149826049804688,99.29989624023438
6,FROM,binary,100,10000,30.114999771118164,30.20949935913086,-0.09449958801269531,99.68717956542969
0,TO,binary,100,10000,35.48400115966797,35.48400115966797,0.0,100.0
1,TO,binary,100,10000,35.38100051879883,35.48400115966797,-0.10300064086914062,99.70972442626953
2,TO,binary,100,10000,35.44499969482422,35.48400115966797,-0.03900146484375,99.89009094238281
3,TO,binary,100,10000,35.359500885009766,35.48400115966797,-0.12450027465820312,99.64913940429688
4,TO,binary,100,10000,35.44049835205078,35.48400115966797,-0.0435028076171875,99.87739562988281
5,TO,binary,100,10000,35.503501892089844,35.48400115966797,0.019500732421875,100.0549545288086
6,TO,binary,100,10000,36.407501220703125,35.48400115966797,0.9235000610351562,102.60257720947266
0,FROM,binary,100,100000,154.4499969482422,154.4499969482422,0.0,100.0
1,FROM,binary,100,100000,165.81500244140625,154.4499969482422,11.365005493164062,107.3583755493164
2,FROM,binary,100,100000,154.42799377441406,154.4499969482422,-0.022003173828125,99.98575592041016
3,FROM,binary,100,100000,154.58999633789062,154.4499969482422,0.1399993896484375,100.09064483642578
4,FROM,binary,100,100000,154.66799926757812,154.4499969482422,0.2180023193359375,100.14114379882812
5,FROM,binary,100,100000,156.05999755859375,154.4499969482422,1.6100006103515625,101.04241180419922
6,FROM,binary,100,100000,156.74600219726562,154.4499969482422,2.2960052490234375,101.48656463623047
0,TO,binary,100,100000,233.7550048828125,233.7550048828125,0.0,100.0
1,TO,binary,100,100000,233.9929962158203,233.7550048828125,0.2379913330078125,100.10181427001953
2,TO,binary,100,100000,234.46400451660156,233.7550048828125,0.7089996337890625,100.30330657958984
3,TO,binary,100,100000,234.406005859375,233.7550048828125,0.6510009765625,100.27849578857422
4,TO,binary,100,100000,235.29200744628906,233.7550048828125,1.5370025634765625,100.65752410888672
5,TO,binary,100,100000,238.656005859375,233.7550048828125,4.9010009765625,102.09664154052734
6,TO,binary,100,100000,239.45799255371094,233.7550048828125,5.7029876708984375,102.43972778320312
0,FROM,binary,100,1000000,1394.719970703125,1394.719970703125,0.0,100.0
1,FROM,binary,100,1000000,1509.0360107421875,1394.719970703125,114.3160400390625,108.19634246826172
2,FROM,binary,100,1000000,1395.7669677734375,1394.719970703125,1.0469970703125,100.07506561279297
3,FROM,binary,100,1000000,1399.2509765625,1394.719970703125,4.531005859375,100.32486724853516
4,FROM,binary,100,1000000,1399.0260009765625,1394.719970703125,4.3060302734375,100.3087387084961
5,FROM,binary,100,1000000,1418.593017578125,1394.719970703125,23.873046875,101.71167755126953
6,FROM,binary,100,1000000,1419.14697265625,1394.719970703125,24.427001953125,101.75138854980469
0,TO,binary,100,1000000,2196.60791015625,2196.60791015625,0.0,100.0
1,TO,binary,100,1000000,2200.14794921875,2196.60791015625,3.5400390625,100.1611557006836
2,TO,binary,100,1000000,2201.35693359375,2196.60791015625,4.7490234375,100.21620178222656
3,TO,binary,100,1000000,2210.639892578125,2196.60791015625,14.031982421875,100.63880920410156
4,TO,binary,100,1000000,2200.174072265625,2196.60791015625,3.566162109375,100.162353515625
5,TO,binary,100,1000000,2224.947998046875,2196.60791015625,28.340087890625,101.29017639160156
6,TO,binary,100,1000000,2253.72802734375,2196.60791015625,57.1201171875,102.60038757324219
0,FROM,csv,1,10,13.416000366210938,13.416000366210938,0.0,100.0
1,FROM,csv,1,10,13.468999862670898,13.416000366210938,0.05299949645996094,100.39505004882812
2,FROM,csv,1,10,13.343000411987305,13.416000366210938,-0.07299995422363281,99.45587158203125
3,FROM,csv,1,10,13.482000350952148,13.416000366210938,0.06599998474121094,100.49195098876953
4,FROM,csv,1,10,13.371999740600586,13.416000366210938,-0.04400062561035156,99.67202758789062
5,FROM,csv,1,10,13.333999633789062,13.416000366210938,-0.082000732421875,99.38878631591797
6,FROM,csv,1,10,13.397000312805176,13.416000366210938,-0.01900005340576172,99.85838317871094
0,TO,csv,1,10,13.062000274658203,13.062000274658203,0.0,100.0
1,TO,csv,1,10,13.006999969482422,13.062000274658203,-0.05500030517578125,99.57892608642578
2,TO,csv,1,10,13.119000434875488,13.062000274658203,0.057000160217285156,100.4363784790039
3,TO,csv,1,10,13.104000091552734,13.062000274658203,0.04199981689453125,100.32154083251953
4,TO,csv,1,10,13.116999626159668,13.062000274658203,0.054999351501464844,100.42105865478516
5,TO,csv,1,10,13.154999732971191,13.062000274658203,0.09299945831298828,100.71199035644531
6,TO,csv,1,10,13.102999687194824,13.062000274658203,0.040999412536621094,100.31388092041016
0,FROM,csv,1,100,13.526000022888184,13.526000022888184,0.0,100.0
1,FROM,csv,1,100,13.479999542236328,13.526000022888184,-0.04600048065185547,99.65990447998047
2,FROM,csv,1,100,13.446000099182129,13.526000022888184,-0.07999992370605469,99.4085464477539
3,FROM,csv,1,100,13.432000160217285,13.526000022888184,-0.09399986267089844,99.30504608154297
4,FROM,csv,1,100,13.57699966430664,13.526000022888184,0.05099964141845703,100.37704467773438
5,FROM,csv,1,100,13.423999786376953,13.526000022888184,-0.10200023651123047,99.24589538574219
6,FROM,csv,1,100,13.640000343322754,13.526000022888184,0.11400032043457031,100.84281921386719
0,TO,csv,1,100,13.246000289916992,13.246000289916992,0.0,100.0
1,TO,csv,1,100,13.159000396728516,13.246000289916992,-0.08699989318847656,99.34320068359375
2,TO,csv,1,100,13.0649995803833,13.246000289916992,-0.1810007095336914,98.633544921875
3,TO,csv,1,100,12.977999687194824,13.246000289916992,-0.26800060272216797,97.97674560546875
4,TO,csv,1,100,13.03600025177002,13.246000289916992,-0.21000003814697266,98.41461944580078
5,TO,csv,1,100,12.984000205993652,13.246000289916992,-0.26200008392333984,98.02204132080078
6,TO,csv,1,100,13.07800006866455,13.246000289916992,-0.1680002212524414,98.731689453125
0,FROM,csv,1,1000,15.562999725341797,15.562999725341797,0.0,100.0
1,FROM,csv,1,1000,15.619999885559082,15.562999725341797,0.057000160217285156,100.36625671386719
2,FROM,csv,1,1000,15.534000396728516,15.562999725341797,-0.02899932861328125,99.81366729736328
3,FROM,csv,1,1000,15.50100040435791,15.562999725341797,-0.06199932098388672,99.60162353515625
4,FROM,csv,1,1000,15.538000106811523,15.562999725341797,-0.024999618530273438,99.83936309814453
5,FROM,csv,1,1000,15.538000106811523,15.562999725341797,-0.024999618530273438,99.83936309814453
6,FROM,csv,1,1000,15.515000343322754,15.562999725341797,-0.04799938201904297,99.69158172607422
0,TO,csv,1,1000,13.130000114440918,13.130000114440918,0.0,100.0
1,TO,csv,1,1000,13.206000328063965,13.130000114440918,0.07600021362304688,100.5788345336914
2,TO,csv,1,1000,13.065999984741211,13.130000114440918,-0.06400012969970703,99.51256561279297
3,TO,csv,1,1000,13.11400032043457,13.130000114440918,-0.015999794006347656,99.87814331054688
4,TO,csv,1,1000,13.206999778747559,13.130000114440918,0.07699966430664062,100.58644104003906
5,TO,csv,1,1000,13.164999961853027,13.130000114440918,0.034999847412109375,100.26656341552734
6,TO,csv,1,1000,13.208999633789062,13.130000114440918,0.07899951934814453,100.60166931152344
0,FROM,csv,1,10000,16.100500106811523,16.100500106811523,0.0,100.0
1,FROM,csv,1,10000,16.101999282836914,16.100500106811523,0.001499176025390625,100.00930786132812
2,FROM,csv,1,10000,16.0885009765625,16.100500106811523,-0.011999130249023438,99.92547607421875
3,FROM,csv,1,10000,16.082000732421875,16.100500106811523,-0.018499374389648438,99.88510131835938
4,FROM,csv,1,10000,16.094499588012695,16.100500106811523,-0.006000518798828125,99.96273040771484
5,FROM,csv,1,10000,16.01099967956543,16.100500106811523,-0.08950042724609375,99.4441146850586
6,FROM,csv,1,10000,16.138500213623047,16.100500106811523,0.03800010681152344,100.23602294921875
0,TO,csv,1,10000,14.024499893188477,14.024499893188477,0.0,100.0
1,TO,csv,1,10000,13.954999923706055,14.024499893188477,-0.06949996948242188,99.50444030761719
2,TO,csv,1,10000,13.920499801635742,14.024499893188477,-0.10400009155273438,99.25843811035156
3,TO,csv,1,10000,13.878999710083008,14.024499893188477,-0.14550018310546875,98.9625244140625
4,TO,csv,1,10000,13.993000030517578,14.024499893188477,-0.03149986267089844,99.775390625
5,TO,csv,1,10000,13.968500137329102,14.024499893188477,-0.055999755859375,99.60070037841797
6,TO,csv,1,10000,13.98449993133545,14.024499893188477,-0.039999961853027344,99.71478271484375
0,FROM,csv,1,100000,21.625999450683594,21.625999450683594,0.0,100.0
1,FROM,csv,1,100000,21.649999618530273,21.625999450683594,0.024000167846679688,100.1109848022461
2,FROM,csv,1,100000,21.865999221801758,21.625999450683594,0.23999977111816406,101.10977935791016
3,FROM,csv,1,100000,22.000999450683594,21.625999450683594,0.375,101.73401641845703
4,FROM,csv,1,100000,21.804000854492188,21.625999450683594,0.17800140380859375,100.82308959960938
5,FROM,csv,1,100000,21.604000091552734,21.625999450683594,-0.021999359130859375,99.89826965332031
6,FROM,csv,1,100000,21.781999588012695,21.625999450683594,0.15600013732910156,100.72135925292969
0,TO,csv,1,100000,21.92300033569336,21.92300033569336,0.0,100.0
1,TO,csv,1,100000,21.9060001373291,21.92300033569336,-0.017000198364257812,99.92245483398438
2,TO,csv,1,100000,21.77199935913086,21.92300033569336,-0.1510009765625,99.31121826171875
3,TO,csv,1,100000,21.8700008392334,21.92300033569336,-0.05299949645996094,99.75824737548828
4,TO,csv,1,100000,21.981000900268555,21.92300033569336,0.05800056457519531,100.26456451416016
5,TO,csv,1,100000,21.867000579833984,21.92300033569336,-0.055999755859375,99.74456787109375
6,TO,csv,1,100000,21.871000289916992,21.92300033569336,-0.05200004577636719,99.76280212402344
0,FROM,csv,1,1000000,77.24500274658203,77.24500274658203,0.0,100.0
1,FROM,csv,1,1000000,77.48500061035156,77.24500274658203,0.23999786376953125,100.3106918334961
2,FROM,csv,1,1000000,78.73400115966797,77.24500274658203,1.4889984130859375,101.92762756347656
3,FROM,csv,1,1000000,80.88099670410156,77.24500274658203,3.6359939575195312,104.70709991455078
4,FROM,csv,1,1000000,79.21800231933594,77.24500274658203,1.9729995727539062,102.55421447753906
5,FROM,csv,1,1000000,77.6259994506836,77.24500274658203,0.3809967041015625,100.49322509765625
6,FROM,csv,1,1000000,77.6969985961914,77.24500274658203,0.451995849609375,100.58515167236328
0,TO,csv,1,1000000,98.48400115966797,98.48400115966797,0.0,100.0
1,TO,csv,1,1000000,98.36100006103516,98.48400115966797,-0.1230010986328125,99.87510681152344
2,TO,csv,1,1000000,98.177001953125,98.48400115966797,-0.30699920654296875,99.68827056884766
3,TO,csv,1,1000000,98.1449966430664,98.48400115966797,-0.3390045166015625,99.65577697753906
4,TO,csv,1,1000000,99.58000183105469,98.48400115966797,1.0960006713867188,101.11286926269531
5,TO,csv,1,1000000,98.97799682617188,98.48400115966797,0.49399566650390625,100.50159454345703
6,TO,csv,1,1000000,98.76699829101562,98.48400115966797,0.28299713134765625,100.287353515625
0,FROM,csv,10,10,13.317999839782715,13.317999839782715,0.0,100.0
1,FROM,csv,10,10,13.324999809265137,13.317999839782715,0.006999969482421875,100.05255889892578
2,FROM,csv,10,10,13.366999626159668,13.317999839782715,0.048999786376953125,100.36791229248047
3,FROM,csv,10,10,13.282999992370605,13.317999839782715,-0.034999847412109375,99.73719787597656
4,FROM,csv,10,10,14.005000114440918,13.317999839782715,0.6870002746582031,105.15843963623047
5,FROM,csv,10,10,13.303000450134277,13.317999839782715,-0.0149993896484375,99.88737487792969
6,FROM,csv,10,10,13.45199966430664,13.317999839782715,0.13399982452392578,101.00614929199219
0,TO,csv,10,10,13.071000099182129,13.071000099182129,0.0,100.0
1,TO,csv,10,10,12.991000175476074,13.071000099182129,-0.07999992370605469,99.3879623413086
2,TO,csv,10,10,13.038999557495117,13.071000099182129,-0.03200054168701172,99.75518035888672
3,TO,csv,10,10,12.95199966430664,13.071000099182129,-0.11900043487548828,99.08958435058594
4,TO,csv,10,10,13.680999755859375,13.071000099182129,0.6099996566772461,104.66681671142578
5,TO,csv,10,10,12.979999542236328,13.071000099182129,-0.09100055694580078,99.30380249023438
6,TO,csv,10,10,13.140000343322754,13.071000099182129,0.069000244140625,100.52788543701172
0,FROM,csv,10,100,13.46399974822998,13.46399974822998,0.0,100.0
1,FROM,csv,10,100,13.510000228881836,13.46399974822998,0.04600048065185547,100.3416519165039
2,FROM,csv,10,100,13.456999778747559,13.46399974822998,-0.006999969482421875,99.94800567626953
3,FROM,csv,10,100,13.5,13.46399974822998,0.03600025177001953,100.26738739013672
4,FROM,csv,10,100,14.071999549865723,13.46399974822998,0.6079998016357422,104.5157470703125
5,FROM,csv,10,100,13.597000122070312,13.46399974822998,0.13300037384033203,100.98783111572266
6,FROM,csv,10,100,13.541000366210938,13.46399974822998,0.07700061798095703,100.57189178466797
0,TO,csv,10,100,13.085000038146973,13.085000038146973,0.0,100.0
1,TO,csv,10,100,13.062000274658203,13.085000038146973,-0.02299976348876953,99.82422637939453
2,TO,csv,10,100,13.149999618530273,13.085000038146973,0.06499958038330078,100.49674224853516
3,TO,csv,10,100,13.074000358581543,13.085000038146973,-0.010999679565429688,99.91593933105469
4,TO,csv,10,100,13.704999923706055,13.085000038146973,0.619999885559082,104.73825073242188
5,TO,csv,10,100,13.076000213623047,13.085000038146973,-0.008999824523925781,99.93122100830078
6,TO,csv,10,100,13.128000259399414,13.085000038146973,0.043000221252441406,100.32862091064453
0,FROM,csv,10,1000,15.821999549865723,15.821999549865723,0.0,100.0
1,FROM,csv,10,1000,15.802000045776367,15.821999549865723,-0.01999950408935547,99.87359619140625
2,FROM,csv,10,1000,15.746999740600586,15.821999549865723,-0.07499980926513672,99.5259780883789
3,FROM,csv,10,1000,15.72599983215332,15.821999549865723,-0.09599971771240234,99.39325714111328
4,FROM,csv,10,1000,16.489999771118164,15.821999549865723,0.6680002212524414,104.22197723388672
5,FROM,csv,10,1000,15.644000053405762,15.821999549865723,-0.17799949645996094,98.87498474121094
6,FROM,csv,10,1000,15.833000183105469,15.821999549865723,0.011000633239746094,100.06951904296875
0,TO,csv,10,1000,13.279999732971191,13.279999732971191,0.0,100.0
1,TO,csv,10,1000,13.352999687194824,13.279999732971191,0.07299995422363281,100.54969787597656
2,TO,csv,10,1000,13.244999885559082,13.279999732971191,-0.034999847412109375,99.73644256591797
3,TO,csv,10,1000,13.276000022888184,13.279999732971191,-0.0039997100830078125,99.96987915039062
4,TO,csv,10,1000,13.930999755859375,13.279999732971191,0.6510000228881836,104.90211486816406
5,TO,csv,10,1000,13.25,13.279999732971191,-0.029999732971191406,99.77410125732422
6,TO,csv,10,1000,13.369000434875488,13.279999732971191,0.08900070190429688,100.67018127441406
0,FROM,csv,10,10000,17.78849983215332,17.78849983215332,0.0,100.0
1,FROM,csv,10,10000,17.85449981689453,17.78849983215332,0.06599998474121094,100.37102508544922
2,FROM,csv,10,10000,17.717498779296875,17.78849983215332,-0.07100105285644531,99.60086059570312
3,FROM,csv,10,10000,17.814498901367188,17.78849983215332,0.025999069213867188,100.14616394042969
4,FROM,csv,10,10000,18.626998901367188,17.78849983215332,0.8384990692138672,104.71371459960938
5,FROM,csv,10,10000,17.723499298095703,17.78849983215332,-0.06500053405761719,99.63459014892578
6,FROM,csv,10,10000,17.79199981689453,17.78849983215332,0.0034999847412109375,100.01968383789062
0,TO,csv,10,10000,15.640000343322754,15.640000343322754,0.0,100.0
1,TO,csv,10,10000,15.495500564575195,15.640000343322754,-0.1444997787475586,99.07608795166016
2,TO,csv,10,10000,15.509500503540039,15.640000343322754,-0.13049983978271484,99.16560363769531
3,TO,csv,10,10000,15.57450008392334,15.640000343322754,-0.06550025939941406,99.5811996459961
4,TO,csv,10,10000,16.314498901367188,15.640000343322754,0.6744985580444336,104.3126449584961
5,TO,csv,10,10000,15.53499984741211,15.640000343322754,-0.10500049591064453,99.32864379882812
6,TO,csv,10,10000,15.589000701904297,15.640000343322754,-0.05099964141845703,99.67391204833984
0,FROM,csv,10,100000,37.849998474121094,37.849998474121094,0.0,100.0
1,FROM,csv,10,100000,38.04399871826172,37.849998474121094,0.194000244140625,100.5125503540039
2,FROM,csv,10,100000,37.9119987487793,37.849998474121094,0.062000274658203125,100.16380310058594
3,FROM,csv,10,100000,38.15599822998047,37.849998474121094,0.305999755859375,100.80845642089844
4,FROM,csv,10,100000,39.17300033569336,37.849998474121094,1.3230018615722656,103.4953842163086
5,FROM,csv,10,100000,37.98899841308594,37.849998474121094,0.13899993896484375,100.36723327636719
6,FROM,csv,10,100000,38.137001037597656,37.849998474121094,0.2870025634765625,100.75827026367188
0,TO,csv,10,100000,37.87799835205078,37.87799835205078,0.0,100.0
1,TO,csv,10,100000,37.4630012512207,37.87799835205078,-0.4149971008300781,98.90438079833984
2,TO,csv,10,100000,37.60300064086914,37.87799835205078,-0.2749977111816406,99.27399444580078
3,TO,csv,10,100000,37.62300109863281,37.87799835205078,-0.25499725341796875,99.32679748535156
4,TO,csv,10,100000,38.81100082397461,37.87799835205078,0.9330024719238281,102.46317291259766
5,TO,csv,10,100000,37.902000427246094,37.87799835205078,0.0240020751953125,100.06336975097656
6,TO,csv,10,100000,37.86800003051758,37.87799835205078,-0.009998321533203125,99.97360229492188
0,FROM,csv,10,1000000,237.47500610351562,237.47500610351562,0.0,100.0
1,FROM,csv,10,1000000,237.21400451660156,237.47500610351562,-0.2610015869140625,99.89009857177734
2,FROM,csv,10,1000000,239.30999755859375,237.47500610351562,1.834991455078125,100.77271270751953
3,FROM,csv,10,1000000,241.11199951171875,237.47500610351562,3.636993408203125,101.53153228759766
4,FROM,csv,10,1000000,242.98300170898438,237.47500610351562,5.50799560546875,102.31939697265625
5,FROM,csv,10,1000000,238.8489990234375,237.47500610351562,1.373992919921875,100.57858276367188
6,FROM,csv,10,1000000,241.37899780273438,237.47500610351562,3.90399169921875,101.64395904541016
0,TO,csv,10,1000000,255.8939971923828,255.8939971923828,0.0,100.0
1,TO,csv,10,1000000,253.2310028076172,255.8939971923828,-2.662994384765625,98.95933532714844
2,TO,csv,10,1000000,253.5959930419922,255.8939971923828,-2.298004150390625,99.10197448730469
3,TO,csv,10,1000000,253.85000610351562,255.8939971923828,-2.0439910888671875,99.20124053955078
4,TO,csv,10,1000000,258.0790100097656,255.8939971923828,2.1850128173828125,100.85387420654297
5,TO,csv,10,1000000,257.9209899902344,255.8939971923828,2.0269927978515625,100.79212188720703
6,TO,csv,10,1000000,259.8479919433594,255.8939971923828,3.9539947509765625,101.545166015625
0,FROM,csv,100,10,13.711000442504883,13.711000442504883,0.0,100.0
1,FROM,csv,100,10,13.49899959564209,13.711000442504883,-0.21200084686279297,98.45378875732422
2,FROM,csv,100,10,13.4350004196167,13.711000442504883,-0.2760000228881836,97.98702239990234
3,FROM,csv,100,10,13.423999786376953,13.711000442504883,-0.2870006561279297,97.90678405761719
4,FROM,csv,100,10,13.666999816894531,13.711000442504883,-0.04400062561035156,99.67908477783203
5,FROM,csv,100,10,13.329000473022461,13.711000442504883,-0.3819999694824219,97.21392059326172
6,FROM,csv,100,10,13.532999992370605,13.711000442504883,-0.17800045013427734,98.70176696777344
0,TO,csv,100,10,13.173999786376953,13.173999786376953,0.0,100.0
1,TO,csv,100,10,13.13599967956543,13.173999786376953,-0.03800010681152344,99.7115478515625
2,TO,csv,100,10,13.064000129699707,13.173999786376953,-0.1099996566772461,99.16502380371094
3,TO,csv,100,10,13.079999923706055,13.173999786376953,-0.09399986267089844,99.2864761352539
4,TO,csv,100,10,13.368000030517578,13.173999786376953,0.194000244140625,101.47260284423828
5,TO,csv,100,10,13.109999656677246,13.173999786376953,-0.06400012969970703,99.51419067382812
6,TO,csv,100,10,13.166000366210938,13.173999786376953,-0.007999420166015625,99.93927764892578
0,FROM,csv,100,100,13.87600040435791,13.87600040435791,0.0,100.0
1,FROM,csv,100,100,13.805999755859375,13.87600040435791,-0.07000064849853516,99.49552917480469
2,FROM,csv,100,100,13.734000205993652,13.87600040435791,-0.1420001983642578,98.97664642333984
3,FROM,csv,100,100,13.791999816894531,13.87600040435791,-0.0840005874633789,99.3946304321289
4,FROM,csv,100,100,14.189000129699707,13.87600040435791,0.3129997253417969,102.25569152832031
5,FROM,csv,100,100,13.663000106811523,13.87600040435791,-0.21300029754638672,98.46497344970703
6,FROM,csv,100,100,13.793999671936035,13.87600040435791,-0.082000732421875,99.40904235839844
0,TO,csv,100,100,13.236000061035156,13.236000061035156,0.0,100.0
1,TO,csv,100,100,13.288999557495117,13.236000061035156,0.05299949645996094,100.40042114257812
2,TO,csv,100,100,13.20300006866455,13.236000061035156,-0.03299999237060547,99.75067901611328
3,TO,csv,100,100,13.277999877929688,13.236000061035156,0.04199981689453125,100.31731414794922
4,TO,csv,100,100,13.39799976348877,13.236000061035156,0.16199970245361328,101.22393035888672
5,TO,csv,100,100,13.241000175476074,13.236000061035156,0.005000114440917969,100.03778076171875
6,TO,csv,100,100,13.300000190734863,13.236000061035156,0.06400012969970703,100.48352813720703
0,FROM,csv,100,1000,16.042999267578125,16.042999267578125,0.0,100.0
1,FROM,csv,100,1000,16.08099937438965,16.042999267578125,0.03800010681152344,100.23686981201172
2,FROM,csv,100,1000,15.925999641418457,16.042999267578125,-0.11699962615966797,99.27071380615234
3,FROM,csv,100,1000,16.121999740600586,16.042999267578125,0.07900047302246094,100.492431640625
4,FROM,csv,100,1000,16.645000457763672,16.042999267578125,0.6020011901855469,103.75242614746094
5,FROM,csv,100,1000,15.859000205993652,16.042999267578125,-0.18399906158447266,98.85308837890625
6,FROM,csv,100,1000,16.027999877929688,16.042999267578125,-0.0149993896484375,99.90650177001953
0,TO,csv,100,1000,14.9399995803833,14.9399995803833,0.0,100.0
1,TO,csv,100,1000,14.965999603271484,14.9399995803833,0.026000022888183594,100.17403411865234
2,TO,csv,100,1000,15.00100040435791,14.9399995803833,0.061000823974609375,100.4083023071289
3,TO,csv,100,1000,14.888999938964844,14.9399995803833,-0.05099964141845703,99.65863800048828
4,TO,csv,100,1000,15.631999969482422,14.9399995803833,0.6920003890991211,104.63186645507812
5,TO,csv,100,1000,14.763999938964844,14.9399995803833,-0.17599964141845703,98.82195281982422
6,TO,csv,100,1000,15.031000137329102,14.9399995803833,0.09100055694580078,100.60911560058594
0,FROM,csv,100,10000,33.66600036621094,33.66600036621094,0.0,100.0
1,FROM,csv,100,10000,33.64350128173828,33.66600036621094,-0.02249908447265625,99.93317413330078
2,FROM,csv,100,10000,33.84749984741211,33.66600036621094,0.18149948120117188,100.53910827636719
3,FROM,csv,100,10000,33.876502990722656,33.66600036621094,0.21050262451171875,100.6252670288086
4,FROM,csv,100,10000,34.894500732421875,33.66600036621094,1.2285003662109375,103.64907836914062
5,FROM,csv,100,10000,33.87099838256836,33.66600036621094,0.20499801635742188,100.60891723632812
6,FROM,csv,100,10000,33.88249969482422,33.66600036621094,0.21649932861328125,100.64307403564453
0,TO,csv,100,10000,31.034000396728516,31.034000396728516,0.0,100.0
1,TO,csv,100,10000,30.602500915527344,31.034000396728516,-0.4314994812011719,98.60958862304688
2,TO,csv,100,10000,30.5364990234375,31.034000396728516,-0.4975013732910156,98.39691162109375
3,TO,csv,100,10000,30.57849884033203,31.034000396728516,-0.4555015563964844,98.5322494506836
4,TO,csv,100,10000,31.582500457763672,31.034000396728516,0.5485000610351562,101.76741790771484
5,TO,csv,100,10000,30.85900115966797,31.034000396728516,-0.17499923706054688,99.43610382080078
6,TO,csv,100,10000,30.94849967956543,31.034000396728516,-0.08550071716308594,99.72449493408203
0,FROM,csv,100,100000,209.28500366210938,209.28500366210938,0.0,100.0
1,FROM,csv,100,100000,210.75399780273438,209.28500366210938,1.468994140625,100.70191955566406
2,FROM,csv,100,100000,212.6999969482422,209.28500366210938,3.4149932861328125,101.63175201416016
3,FROM,csv,100,100000,212.25900268554688,209.28500366210938,2.9739990234375,101.4210205078125
4,FROM,csv,100,100000,211.98899841308594,209.28500366210938,2.7039947509765625,101.2920150756836
5,FROM,csv,100,100000,212.46099853515625,209.28500366210938,3.175994873046875,101.51754760742188
6,FROM,csv,100,100000,210.3820037841797,209.28500366210938,1.0970001220703125,100.52416229248047
0,TO,csv,100,100000,189.81900024414062,189.81900024414062,0.0,100.0
1,TO,csv,100,100000,186.75999450683594,189.81900024414062,-3.0590057373046875,98.38846588134766
2,TO,csv,100,100000,187.49099731445312,189.81900024414062,-2.3280029296875,98.77356719970703
3,TO,csv,100,100000,188.0709991455078,189.81900024414062,-1.7480010986328125,99.07911682128906
4,TO,csv,100,100000,188.0070037841797,189.81900024414062,-1.8119964599609375,99.04541015625
5,TO,csv,100,100000,192.1909942626953,189.81900024414062,2.3719940185546875,101.2496109008789
6,TO,csv,100,100000,192.6199951171875,189.81900024414062,2.800994873046875,101.4756088256836
0,FROM,csv,100,1000000,1970.5030517578125,1970.5030517578125,0.0,100.0
1,FROM,csv,100,1000000,1974.2869873046875,1970.5030517578125,3.783935546875,100.19203186035156
2,FROM,csv,100,1000000,2002.7239990234375,1970.5030517578125,32.220947265625,101.6351547241211
3,FROM,csv,100,1000000,1993.18701171875,1970.5030517578125,22.6839599609375,101.15118408203125
4,FROM,csv,100,1000000,1997.27294921875,1970.5030517578125,26.7698974609375,101.35853576660156
5,FROM,csv,100,1000000,1996.092041015625,1970.5030517578125,25.5889892578125,101.2986068725586
6,FROM,csv,100,1000000,1977.8919677734375,1970.5030517578125,7.388916015625,100.37496948242188
0,TO,csv,100,1000000,1758.9000244140625,1758.9000244140625,0.0,100.0
1,TO,csv,100,1000000,1733.511962890625,1758.9000244140625,-25.3880615234375,98.55659484863281
2,TO,csv,100,1000000,1747.6259765625,1758.9000244140625,-11.2740478515625,99.3590316772461
3,TO,csv,100,1000000,1754.7149658203125,1758.9000244140625,-4.18505859375,99.7620620727539
4,TO,csv,100,1000000,1755.362060546875,1758.9000244140625,-3.5379638671875,99.7988510131836
5,TO,csv,100,1000000,1763.3310546875,1758.9000244140625,4.4310302734375,100.25192260742188
6,TO,csv,100,1000000,1771.4189453125,1758.9000244140625,12.5189208984375,100.71175384521484
0,FROM,text,1,10,14.28499984741211,14.28499984741211,0.0,100.0
1,FROM,text,1,10,13.776000022888184,14.28499984741211,-0.5089998245239258,96.43682098388672
2,FROM,text,1,10,14.145999908447266,14.28499984741211,-0.13899993896484375,99.0269546508789
3,FROM,text,1,10,14.326000213623047,14.28499984741211,0.0410003662109375,100.28701782226562
4,FROM,text,1,10,13.437999725341797,14.28499984741211,-0.8470001220703125,94.0707015991211
5,FROM,text,1,10,14.008999824523926,14.28499984741211,-0.2760000228881836,98.06790161132812
6,FROM,text,1,10,13.645000457763672,14.28499984741211,-0.6399993896484375,95.51978302001953
0,TO,text,1,10,14.305000305175781,14.305000305175781,0.0,100.0
1,TO,text,1,10,13.222000122070312,14.305000305175781,-1.0830001831054688,92.4292221069336
2,TO,text,1,10,13.907999992370605,14.305000305175781,-0.3970003128051758,97.22473907470703
3,TO,text,1,10,14.244999885559082,14.305000305175781,-0.06000041961669922,99.58055877685547
4,TO,text,1,10,13.470999717712402,14.305000305175781,-0.8340005874633789,94.16986846923828
5,TO,text,1,10,14.192000389099121,14.305000305175781,-0.11299991607666016,99.21006774902344
6,TO,text,1,10,13.359999656677246,14.305000305175781,-0.9450006484985352,93.39391326904297
0,FROM,text,1,100,14.38700008392334,14.38700008392334,0.0,100.0
1,FROM,text,1,100,14.154999732971191,14.38700008392334,-0.23200035095214844,98.38743591308594
2,FROM,text,1,100,14.52299976348877,14.38700008392334,0.1359996795654297,100.94529724121094
3,FROM,text,1,100,14.38599967956543,14.38700008392334,-0.0010004043579101562,99.9930419921875
4,FROM,text,1,100,13.581999778747559,14.38700008392334,-0.8050003051757812,94.40467071533203
5,FROM,text,1,100,14.472999572753906,14.38700008392334,0.0859994888305664,100.59776306152344
6,FROM,text,1,100,14.003999710083008,14.38700008392334,-0.38300037384033203,97.33787536621094
0,TO,text,1,100,14.085000038146973,14.085000038146973,0.0,100.0
1,TO,text,1,100,13.574000358581543,14.085000038146973,-0.5109996795654297,96.37203216552734
2,TO,text,1,100,13.9350004196167,14.085000038146973,-0.14999961853027344,98.9350357055664
3,TO,text,1,100,13.875,14.085000038146973,-0.21000003814697266,98.50904846191406
4,TO,text,1,100,13.140000343322754,14.085000038146973,-0.9449996948242188,93.29073333740234
5,TO,text,1,100,13.9399995803833,14.085000038146973,-0.14500045776367188,98.97053527832031
6,TO,text,1,100,13.689000129699707,14.085000038146973,-0.3959999084472656,97.1884994506836
0,FROM,text,1,1000,15.866000175476074,15.866000175476074,0.0,100.0
1,FROM,text,1,1000,16.349000930786133,15.866000175476074,0.4830007553100586,103.04425048828125
2,FROM,text,1,1000,15.798999786376953,15.866000175476074,-0.0670003890991211,99.57771301269531
3,FROM,text,1,1000,16.440000534057617,15.866000175476074,0.574000358581543,103.6177978515625
4,FROM,text,1,1000,15.571999549865723,15.866000175476074,-0.29400062561035156,98.14697265625
5,FROM,text,1,1000,16.05900001525879,15.866000175476074,0.19299983978271484,101.21643829345703
6,FROM,text,1,1000,16.333999633789062,15.866000175476074,0.4679994583129883,102.94969940185547
0,TO,text,1,1000,13.645999908447266,13.645999908447266,0.0,100.0
1,TO,text,1,1000,14.076000213623047,13.645999908447266,0.43000030517578125,103.15110778808594
2,TO,text,1,1000,13.831999778747559,13.645999908447266,0.18599987030029297,101.363037109375
3,TO,text,1,1000,14.081999778747559,13.645999908447266,0.43599987030029297,103.195068359375
4,TO,text,1,1000,13.149999618530273,13.645999908447266,-0.4960002899169922,96.365234375
5,TO,text,1,1000,13.972999572753906,13.645999908447266,0.3269996643066406,102.39630889892578
6,TO,text,1,1000,14.194000244140625,13.645999908447266,0.5480003356933594,104.01582336425781
0,FROM,text,1,10000,16.470500946044922,16.470500946044922,0.0,100.0
1,FROM,text,1,10000,17.092998504638672,16.470500946044922,0.62249755859375,103.77947235107422
2,FROM,text,1,10000,16.184499740600586,16.470500946044922,-0.28600120544433594,98.26355743408203
3,FROM,text,1,10000,15.774999618530273,16.470500946044922,-0.6955013275146484,95.77729034423828
4,FROM,text,1,10000,16.172000885009766,16.470500946044922,-0.29850006103515625,98.18766784667969
5,FROM,text,1,10000,16.18400001525879,16.470500946044922,-0.2865009307861328,98.2605209350586
6,FROM,text,1,10000,17.15250015258789,16.470500946044922,0.6819992065429688,104.14073181152344
0,TO,text,1,10000,14.608999252319336,14.608999252319336,0.0,100.0
1,TO,text,1,10000,14.874000549316406,14.608999252319336,0.2650012969970703,101.81395721435547
2,TO,text,1,10000,14.342000007629395,14.608999252319336,-0.2669992446899414,98.17236328125
3,TO,text,1,10000,14.121999740600586,14.608999252319336,-0.48699951171875,96.66644287109375
4,TO,text,1,10000,13.935500144958496,14.608999252319336,-0.6734991073608398,95.38983917236328
5,TO,text,1,10000,14.121999740600586,14.608999252319336,-0.48699951171875,96.66644287109375
6,TO,text,1,10000,14.814000129699707,14.608999252319336,0.2050008773803711,101.40325164794922
0,FROM,text,1,100000,22.172000885009766,22.172000885009766,0.0,100.0
1,FROM,text,1,100000,22.766000747680664,22.172000885009766,0.5939998626708984,102.67904663085938
2,FROM,text,1,100000,22.263999938964844,22.172000885009766,0.09199905395507812,100.41493225097656
3,FROM,text,1,100000,22.325000762939453,22.172000885009766,0.1529998779296875,100.69005584716797
4,FROM,text,1,100000,21.610000610351562,22.172000885009766,-0.5620002746582031,97.46527099609375
5,FROM,text,1,100000,22.158000946044922,22.172000885009766,-0.01399993896484375,99.93685150146484
6,FROM,text,1,100000,22.79199981689453,22.172000885009766,0.6199989318847656,102.79631805419922
0,TO,text,1,100000,21.731000900268555,21.731000900268555,0.0,100.0
1,TO,text,1,100000,22.06599998474121,21.731000900268555,0.33499908447265625,101.54156494140625
2,TO,text,1,100000,21.645000457763672,21.731000900268555,-0.08600044250488281,99.604248046875
3,TO,text,1,100000,21.709999084472656,21.731000900268555,-0.021001815795898438,99.90335845947266
4,TO,text,1,100000,21.483999252319336,21.731000900268555,-0.24700164794921875,98.86337280273438
5,TO,text,1,100000,21.732999801635742,21.731000900268555,0.0019989013671875,100.00920104980469
6,TO,text,1,100000,22.042999267578125,21.731000900268555,0.3119983673095703,101.43572998046875
0,FROM,text,1,1000000,77.09700012207031,77.09700012207031,0.0,100.0
1,FROM,text,1,1000000,76.04399871826172,77.09700012207031,-1.0530014038085938,98.63418579101562
2,FROM,text,1,1000000,78.62000274658203,77.09700012207031,1.5230026245117188,101.9754409790039
3,FROM,text,1,1000000,80.06500244140625,77.09700012207031,2.9680023193359375,103.84970092773438
4,FROM,text,1,1000000,75.83300018310547,77.09700012207031,-1.2639999389648438,98.36051177978516
5,FROM,text,1,1000000,78.68099975585938,77.09700012207031,1.5839996337890625,102.05455017089844
6,FROM,text,1,1000000,76.6780014038086,77.09700012207031,-0.41899871826171875,99.45652770996094
0,TO,text,1,1000000,93.53900146484375,93.53900146484375,0.0,100.0
1,TO,text,1,1000000,91.98999786376953,93.53900146484375,-1.5490036010742188,98.34400177001953
2,TO,text,1,1000000,93.3499984741211,93.53900146484375,-0.18900299072265625,99.79794311523438
3,TO,text,1,1000000,93.0459976196289,93.53900146484375,-0.49300384521484375,99.47294616699219
4,TO,text,1,1000000,92.48600006103516,93.53900146484375,-1.0530014038085938,98.874267578125
5,TO,text,1,1000000,93.20800018310547,93.53900146484375,-0.33100128173828125,99.64613342285156
6,TO,text,1,1000000,92.10600280761719,93.53900146484375,-1.4329986572265625,98.468017578125
0,FROM,text,10,10,14.319999694824219,14.319999694824219,0.0,100.0
1,FROM,text,10,10,13.059000015258789,14.319999694824219,-1.2609996795654297,91.19413757324219
2,FROM,text,10,10,14.229000091552734,14.319999694824219,-0.09099960327148438,99.3645248413086
3,FROM,text,10,10,14.312000274658203,14.319999694824219,-0.007999420166015625,99.94413757324219
4,FROM,text,10,10,13.317999839782715,14.319999694824219,-1.001999855041504,93.00279235839844
5,FROM,text,10,10,14.574000358581543,14.319999694824219,0.2540006637573242,101.77375030517578
6,FROM,text,10,10,13.125,14.319999694824219,-1.1949996948242188,91.655029296875
0,TO,text,10,10,14.086000442504883,14.086000442504883,0.0,100.0
1,TO,text,10,10,12.753999710083008,14.086000442504883,-1.332000732421875,90.54379272460938
2,TO,text,10,10,14.135000228881836,14.086000442504883,0.048999786376953125,100.34786224365234
3,TO,text,10,10,13.96399974822998,14.086000442504883,-0.12200069427490234,99.1338882446289
4,TO,text,10,10,13.050999641418457,14.086000442504883,-1.0350008010864258,92.65227508544922
5,TO,text,10,10,13.961000442504883,14.086000442504883,-0.125,99.11259460449219
6,TO,text,10,10,12.88599967956543,14.086000442504883,-1.2000007629394531,91.48089599609375
0,FROM,text,10,100,14.439000129699707,14.439000129699707,0.0,100.0
1,FROM,text,10,100,13.173999786376953,14.439000129699707,-1.265000343322754,91.23900604248047
2,FROM,text,10,100,14.23799991607666,14.439000129699707,-0.20100021362304688,98.6079330444336
3,FROM,text,10,100,13.946999549865723,14.439000129699707,-0.4920005798339844,96.59255981445312
4,FROM,text,10,100,13.579000473022461,14.439000129699707,-0.8599996566772461,94.04390716552734
5,FROM,text,10,100,14.218000411987305,14.439000129699707,-0.22099971771240234,98.46942138671875
6,FROM,text,10,100,13.586999893188477,14.439000129699707,-0.8520002365112305,94.09931182861328
0,TO,text,10,100,14.04699993133545,14.04699993133545,0.0,100.0
1,TO,text,10,100,12.920000076293945,14.04699993133545,-1.126999855041504,91.97693634033203
2,TO,text,10,100,14.07699966430664,14.04699993133545,0.029999732971191406,100.21356201171875
3,TO,text,10,100,14.270999908447266,14.04699993133545,0.2239999771118164,101.59465026855469
4,TO,text,10,100,13.11299991607666,14.04699993133545,-0.9340000152587891,93.35089111328125
5,TO,text,10,100,13.37399959564209,14.04699993133545,-0.6730003356933594,95.20893859863281
6,TO,text,10,100,12.734000205993652,14.04699993133545,-1.3129997253417969,90.6528091430664
0,FROM,text,10,1000,15.303000450134277,15.303000450134277,0.0,100.0
1,FROM,text,10,1000,15.432999610900879,15.303000450134277,0.12999916076660156,100.84949493408203
2,FROM,text,10,1000,15.784000396728516,15.303000450134277,0.4809999465942383,103.14318084716797
3,FROM,text,10,1000,15.565999984741211,15.303000450134277,0.2629995346069336,101.71861267089844
4,FROM,text,10,1000,15.798999786376953,15.303000450134277,0.4959993362426758,103.24119567871094
5,FROM,text,10,1000,15.343999862670898,15.303000450134277,0.040999412536621094,100.2679214477539
6,FROM,text,10,1000,15.480999946594238,15.303000450134277,0.17799949645996094,101.16316986083984
0,TO,text,10,1000,13.32800006866455,13.32800006866455,0.0,100.0
1,TO,text,10,1000,12.937999725341797,13.32800006866455,-0.3900003433227539,97.0738296508789
2,TO,text,10,1000,12.961000442504883,13.32800006866455,-0.36699962615966797,97.24639892578125
3,TO,text,10,1000,14.01099967956543,13.32800006866455,0.6829996109008789,105.12454223632812
4,TO,text,10,1000,13.270999908447266,13.32800006866455,-0.057000160217285156,99.57232666015625
5,TO,text,10,1000,13.961000442504883,13.32800006866455,0.633000373840332,104.74940490722656
6,TO,text,10,1000,13.043000221252441,13.32800006866455,-0.2849998474121094,97.86164855957031
0,FROM,text,10,10000,17.363500595092773,17.363500595092773,0.0,100.0
1,FROM,text,10,10000,17.271499633789062,17.363500595092773,-0.09200096130371094,99.47014617919922
2,FROM,text,10,10000,17.262500762939453,17.363500595092773,-0.10099983215332031,99.41831970214844
3,FROM,text,10,10000,17.38599967956543,17.363500595092773,0.02249908447265625,100.12957763671875
4,FROM,text,10,10000,17.52050018310547,17.363500595092773,0.1569995880126953,100.90419006347656
5,FROM,text,10,10000,17.171001434326172,17.363500595092773,-0.19249916076660156,98.891357421875
6,FROM,text,10,10000,17.452999114990234,17.363500595092773,0.08949851989746094,100.51543426513672
0,TO,text,10,10000,14.965999603271484,14.965999603271484,0.0,100.0
1,TO,text,10,10000,15.09000015258789,14.965999603271484,0.12400054931640625,100.82855224609375
2,TO,text,10,10000,14.991000175476074,14.965999603271484,0.025000572204589844,100.16704559326172
3,TO,text,10,10000,15.020999908447266,14.965999603271484,0.05500030517578125,100.36750030517578
4,TO,text,10,10000,15.204000473022461,14.965999603271484,0.23800086975097656,101.59027862548828
5,TO,text,10,10000,14.987500190734863,14.965999603271484,0.021500587463378906,100.14366149902344
6,TO,text,10,10000,15.105499267578125,14.965999603271484,0.13949966430664062,100.9321060180664
0,FROM,text,10,100000,35.07500076293945,35.07500076293945,0.0,100.0
1,FROM,text,10,100000,35.49100112915039,35.07500076293945,0.4160003662109375,101.18602752685547
2,FROM,text,10,100000,34.83300018310547,35.07500076293945,-0.24200057983398438,99.31004333496094
3,FROM,text,10,100000,35.4739990234375,35.07500076293945,0.3989982604980469,101.13755798339844
4,FROM,text,10,100000,35.444000244140625,35.07500076293945,0.3689994812011719,101.05203247070312
5,FROM,text,10,100000,35.055999755859375,35.07500076293945,-0.019001007080078125,99.9458236694336
6,FROM,text,10,100000,35.470001220703125,35.07500076293945,0.3950004577636719,101.12615966796875
0,TO,text,10,100000,34.13600158691406,34.13600158691406,0.0,100.0
1,TO,text,10,100000,34.303001403808594,34.13600158691406,0.16699981689453125,100.48921966552734
2,TO,text,10,100000,34.04999923706055,34.13600158691406,-0.08600234985351562,99.74805450439453
3,TO,text,10,100000,34.16600036621094,34.13600158691406,0.029998779296875,100.08788299560547
4,TO,text,10,100000,34.4370002746582,34.13600158691406,0.3009986877441406,100.88176727294922
5,TO,text,10,100000,34.04999923706055,34.13600158691406,-0.08600234985351562,99.74805450439453
6,TO,text,10,100000,34.0099983215332,34.13600158691406,-0.12600326538085938,99.6308822631836
0,FROM,text,10,1000000,211.4720001220703,211.4720001220703,0.0,100.0
1,FROM,text,10,1000000,212.31100463867188,211.4720001220703,0.8390045166015625,100.39674377441406
2,FROM,text,10,1000000,210.53500366210938,211.4720001220703,-0.9369964599609375,99.55691528320312
3,FROM,text,10,1000000,213.16200256347656,211.4720001220703,1.69000244140625,100.79916381835938
4,FROM,text,10,1000000,211.97999572753906,211.4720001220703,0.50799560546875,100.24021911621094
5,FROM,text,10,1000000,212.4029998779297,211.4720001220703,0.930999755859375,100.44025421142578
6,FROM,text,10,1000000,213.97500610351562,211.4720001220703,2.5030059814453125,101.18360900878906
0,TO,text,10,1000000,220.4669952392578,220.4669952392578,0.0,100.0
1,TO,text,10,1000000,220.8070068359375,220.4669952392578,0.3400115966796875,100.15422058105469
2,TO,text,10,1000000,220.1490020751953,220.4669952392578,-0.3179931640625,99.85576629638672
3,TO,text,10,1000000,221.4499969482422,220.4669952392578,0.983001708984375,100.44586944580078
4,TO,text,10,1000000,221.66799926757812,220.4669952392578,1.2010040283203125,100.54475402832031
5,TO,text,10,1000000,221.93699645996094,220.4669952392578,1.470001220703125,100.66676330566406
6,TO,text,10,1000000,223.91299438476562,220.4669952392578,3.4459991455078125,101.56304931640625
0,FROM,text,100,10,13.42199993133545,13.42199993133545,0.0,100.0
1,FROM,text,100,10,13.430999755859375,13.42199993133545,0.008999824523925781,100.06705474853516
2,FROM,text,100,10,13.527999877929688,13.42199993133545,0.10599994659423828,100.78974914550781
3,FROM,text,100,10,13.50100040435791,13.42199993133545,0.07900047302246094,100.58858489990234
4,FROM,text,100,10,13.475000381469727,13.42199993133545,0.053000450134277344,100.39488220214844
5,FROM,text,100,10,14.13700008392334,13.42199993133545,0.7150001525878906,105.32707977294922
6,FROM,text,100,10,13.513999938964844,13.42199993133545,0.09200000762939453,100.68544006347656
0,TO,text,100,10,13.241000175476074,13.241000175476074,0.0,100.0
1,TO,text,100,10,13.225000381469727,13.241000175476074,-0.015999794006347656,99.87916564941406
2,TO,text,100,10,13.67199993133545,13.241000175476074,0.430999755859375,103.25503540039062
3,TO,text,100,10,13.090999603271484,13.241000175476074,-0.15000057220458984,98.86714935302734
4,TO,text,100,10,13.168999671936035,13.241000175476074,-0.07200050354003906,99.45623016357422
5,TO,text,100,10,14.055999755859375,13.241000175476074,0.8149995803833008,106.15512084960938
6,TO,text,100,10,13.255999565124512,13.241000175476074,0.0149993896484375,100.11328125
0,FROM,text,100,100,13.812999725341797,13.812999725341797,0.0,100.0
1,FROM,text,100,100,13.845999717712402,13.812999725341797,0.03299999237060547,100.23890686035156
2,FROM,text,100,100,13.690999984741211,13.812999725341797,-0.12199974060058594,99.11677551269531
3,FROM,text,100,100,13.708000183105469,13.812999725341797,-0.10499954223632812,99.23985290527344
4,FROM,text,100,100,13.803000450134277,13.812999725341797,-0.009999275207519531,99.9276123046875
5,FROM,text,100,100,14.782999992370605,13.812999725341797,0.9700002670288086,107.02236938476562
6,FROM,text,100,100,13.788000106811523,13.812999725341797,-0.024999618530273438,99.81901550292969
0,TO,text,100,100,13.321000099182129,13.321000099182129,0.0,100.0
1,TO,text,100,100,13.333999633789062,13.321000099182129,0.012999534606933594,100.09758758544922
2,TO,text,100,100,13.560999870300293,13.321000099182129,0.23999977111816406,101.80166625976562
3,TO,text,100,100,13.246999740600586,13.321000099182129,-0.07400035858154297,99.44448852539062
4,TO,text,100,100,13.26099967956543,13.321000099182129,-0.06000041961669922,99.54957580566406
5,TO,text,100,100,13.96399974822998,13.321000099182129,0.6429996490478516,104.82696533203125
6,TO,text,100,100,13.371000289916992,13.321000099182129,0.05000019073486328,100.37535095214844
0,FROM,text,100,1000,15.581000328063965,15.581000328063965,0.0,100.0
1,FROM,text,100,1000,15.699999809265137,15.581000328063965,0.11899948120117188,100.76374816894531
2,FROM,text,100,1000,15.612000465393066,15.581000328063965,0.031000137329101562,100.19895935058594
3,FROM,text,100,1000,15.6899995803833,15.581000328063965,0.10899925231933594,100.69956970214844
4,FROM,text,100,1000,15.581000328063965,15.581000328063965,0.0,100.0
5,FROM,text,100,1000,15.572999954223633,15.581000328063965,-0.008000373840332031,99.94865417480469
6,FROM,text,100,1000,15.694000244140625,15.581000328063965,0.11299991607666016,100.7252426147461
0,TO,text,100,1000,14.633999824523926,14.633999824523926,0.0,100.0
1,TO,text,100,1000,14.821000099182129,14.633999824523926,0.18700027465820312,101.2778549194336
2,TO,text,100,1000,14.661999702453613,14.633999824523926,0.0279998779296875,100.19132995605469
3,TO,text,100,1000,14.631999969482422,14.633999824523926,-0.0019998550415039062,99.98633575439453
4,TO,text,100,1000,14.57699966430664,14.633999824523926,-0.057000160217285156,99.6104965209961
5,TO,text,100,1000,15.041000366210938,14.633999824523926,0.4070005416870117,102.78120422363281
6,TO,text,100,1000,14.623000144958496,14.633999824523926,-0.010999679565429688,99.92483520507812
0,FROM,text,100,10000,29.932498931884766,29.932498931884766,0.0,100.0
1,FROM,text,100,10000,29.914501190185547,29.932498931884766,-0.01799774169921875,99.93987274169922
2,FROM,text,100,10000,29.820999145507812,29.932498931884766,-0.11149978637695312,99.62749481201172
3,FROM,text,100,10000,29.85700035095215,29.932498931884766,-0.07549858093261719,99.74777221679688
4,FROM,text,100,10000,29.927501678466797,29.932498931884766,-0.00499725341796875,99.98330688476562
5,FROM,text,100,10000,29.946500778198242,29.932498931884766,0.014001846313476562,100.0467758178711
6,FROM,text,100,10000,29.885499954223633,29.932498931884766,-0.04699897766113281,99.84298706054688
0,TO,text,100,10000,27.945499420166016,27.945499420166016,0.0,100.0
1,TO,text,100,10000,27.907501220703125,27.945499420166016,-0.037998199462890625,99.86402893066406
2,TO,text,100,10000,27.773998260498047,27.945499420166016,-0.17150115966796875,99.38629913330078
3,TO,text,100,10000,27.820999145507812,27.945499420166016,-0.12450027465820312,99.55448913574219
4,TO,text,100,10000,27.875999450683594,27.945499420166016,-0.06949996948242188,99.75129699707031
5,TO,text,100,10000,27.759998321533203,27.945499420166016,-0.1855010986328125,99.3362045288086
6,TO,text,100,10000,27.897499084472656,27.945499420166016,-0.048000335693359375,99.82823944091797
0,FROM,text,100,100000,171.27200317382812,171.27200317382812,0.0,100.0
1,FROM,text,100,100000,171.3350067138672,171.27200317382812,0.0630035400390625,100.03678894042969
2,FROM,text,100,100000,171.01199340820312,171.27200317382812,-0.260009765625,99.84819030761719
3,FROM,text,100,100000,171.10400390625,171.27200317382812,-0.167999267578125,99.90190887451172
4,FROM,text,100,100000,172.06500244140625,171.27200317382812,0.792999267578125,100.4630126953125
5,FROM,text,100,100000,171.04400634765625,171.27200317382812,-0.227996826171875,99.86688232421875
6,FROM,text,100,100000,172.75100708007812,171.27200317382812,1.47900390625,100.86354064941406
0,TO,text,100,100000,158.7429962158203,158.7429962158203,0.0,100.0
1,TO,text,100,100000,158.66099548339844,158.7429962158203,-0.082000732421875,99.94834899902344
2,TO,text,100,100000,158.59800720214844,158.7429962158203,-0.144989013671875,99.90866088867188
3,TO,text,100,100000,158.71099853515625,158.7429962158203,-0.0319976806640625,99.97984313964844
4,TO,text,100,100000,158.8300018310547,158.7429962158203,0.087005615234375,100.0548095703125
5,TO,text,100,100000,158.60299682617188,158.7429962158203,-0.1399993896484375,99.91181182861328
6,TO,text,100,100000,161.03199768066406,158.7429962158203,2.28900146484375,101.44195556640625
0,FROM,text,100,1000000,1580.7459716796875,1580.7459716796875,0.0,100.0
1,FROM,text,100,1000000,1581.8509521484375,1580.7459716796875,1.10498046875,100.06990051269531
2,FROM,text,100,1000000,1579.666015625,1580.7459716796875,-1.0799560546875,99.93167877197266
3,FROM,text,100,1000000,1580.0260009765625,1580.7459716796875,-0.719970703125,99.95445251464844
4,FROM,text,100,1000000,1584.6669921875,1580.7459716796875,3.9210205078125,100.248046875
5,FROM,text,100,1000000,1580.02001953125,1580.7459716796875,-0.7259521484375,99.95407104492188
6,FROM,text,100,1000000,1580.4239501953125,1580.7459716796875,-0.322021484375,99.97962951660156
0,TO,text,100,1000000,1451.6259765625,1451.6259765625,0.0,100.0
1,TO,text,100,1000000,1450.051025390625,1451.6259765625,-1.574951171875,99.8915023803711
2,TO,text,100,1000000,1453.3199462890625,1451.6259765625,1.6939697265625,100.11669158935547
3,TO,text,100,1000000,1453.762939453125,1451.6259765625,2.136962890625,100.14720916748047
4,TO,text,100,1000000,1460.7440185546875,1451.6259765625,9.1180419921875,100.62812805175781
5,TO,text,100,1000000,1454.39794921875,1451.6259765625,2.77197265625,100.19096374511719
6,TO,text,100,1000000,1470.8990478515625,1451.6259765625,19.2730712890625,101.32769012451172
version,type,format,n_columns,n_rows,runtime,base_runtime,diff_runtime,diff_percentage
0,FROM,binary,1,10,12.664999961853027,12.664999961853027,0.0,100.0
1,FROM,binary,1,10,13.164999961853027,12.664999961853027,0.5,103.94789123535156
2,FROM,binary,1,10,13.380000114440918,12.664999961853027,0.7150001525878906,105.64547729492188
3,FROM,binary,1,10,13.289999961853027,12.664999961853027,0.625,104.93486022949219
4,FROM,binary,1,10,13.312999725341797,12.664999961853027,0.6479997634887695,105.11646270751953
5,FROM,binary,1,10,13.26099967956543,12.664999961853027,0.5959997177124023,104.70587921142578
6,FROM,binary,1,10,13.29699993133545,12.664999961853027,0.6319999694824219,104.99012756347656
0,TO,binary,1,10,12.404999732971191,12.404999732971191,0.0,100.0
1,TO,binary,1,10,12.947999954223633,12.404999732971191,0.5430002212524414,104.37727355957031
2,TO,binary,1,10,13.310999870300293,12.404999732971191,0.9060001373291016,107.30351257324219
3,TO,binary,1,10,13.081000328063965,12.404999732971191,0.6760005950927734,105.44942474365234
4,TO,binary,1,10,13.038999557495117,12.404999732971191,0.6339998245239258,105.11083984375
5,TO,binary,1,10,13.031999588012695,12.404999732971191,0.6269998550415039,105.05441284179688
6,TO,binary,1,10,13.1899995803833,12.404999732971191,0.7849998474121094,106.32809448242188
0,FROM,binary,1,100,12.710000038146973,12.710000038146973,0.0,100.0
1,FROM,binary,1,100,13.336000442504883,12.710000038146973,0.6260004043579102,104.92526245117188
2,FROM,binary,1,100,13.420999526977539,12.710000038146973,0.7109994888305664,105.5940170288086
3,FROM,binary,1,100,13.413999557495117,12.710000038146973,0.7039995193481445,105.5389404296875
4,FROM,binary,1,100,13.37399959564209,12.710000038146973,0.6639995574951172,105.22422790527344
5,FROM,binary,1,100,13.35200023651123,12.710000038146973,0.6420001983642578,105.0511474609375
6,FROM,binary,1,100,13.468999862670898,12.710000038146973,0.7589998245239258,105.97167205810547
0,TO,binary,1,100,12.484000205993652,12.484000205993652,0.0,100.0
1,TO,binary,1,100,12.871999740600586,12.484000205993652,0.3879995346069336,103.10797882080078
2,TO,binary,1,100,13.086999893188477,12.484000205993652,0.6029996871948242,104.83018493652344
3,TO,binary,1,100,12.897000312805176,12.484000205993652,0.41300010681152344,103.30823516845703
4,TO,binary,1,100,12.91100025177002,12.484000205993652,0.4270000457763672,103.42037963867188
5,TO,binary,1,100,12.951000213623047,12.484000205993652,0.46700000762939453,103.74078369140625
6,TO,binary,1,100,13.043000221252441,12.484000205993652,0.5590000152587891,104.47772979736328
0,FROM,binary,1,1000,14.803999900817871,14.803999900817871,0.0,100.0
1,FROM,binary,1,1000,15.420000076293945,14.803999900817871,0.6160001754760742,104.1610336303711
2,FROM,binary,1,1000,15.37399959564209,14.803999900817871,0.5699996948242188,103.85030364990234
3,FROM,binary,1,1000,15.435999870300293,14.803999900817871,0.6319999694824219,104.26911163330078
4,FROM,binary,1,1000,15.331000328063965,14.803999900817871,0.5270004272460938,103.55985260009766
5,FROM,binary,1,1000,15.37600040435791,14.803999900817871,0.5720005035400391,103.86382293701172
6,FROM,binary,1,1000,15.444999694824219,14.803999900817871,0.6409997940063477,104.32991027832031
0,TO,binary,1,1000,12.619999885559082,12.619999885559082,0.0,100.0
1,TO,binary,1,1000,13.020999908447266,12.619999885559082,0.4010000228881836,103.17749786376953
2,TO,binary,1,1000,13.142999649047852,12.619999885559082,0.5229997634887695,104.14421844482422
3,TO,binary,1,1000,13.17300033569336,12.619999885559082,0.5530004501342773,104.38194274902344
4,TO,binary,1,1000,13.017999649047852,12.619999885559082,0.39799976348876953,103.15371704101562
5,TO,binary,1,1000,13.119999885559082,12.619999885559082,0.5,103.96196746826172
6,TO,binary,1,1000,13.133999824523926,12.619999885559082,0.5139999389648438,104.07290649414062
0,FROM,binary,1,10000,15.337499618530273,15.337499618530273,0.0,100.0
1,FROM,binary,1,10000,15.756999969482422,15.337499618530273,0.41950035095214844,102.73512268066406
2,FROM,binary,1,10000,16.030498504638672,15.337499618530273,0.6929988861083984,104.5183334350586
3,FROM,binary,1,10000,15.869999885559082,15.337499618530273,0.5325002670288086,103.47188568115234
4,FROM,binary,1,10000,15.82550048828125,15.337499618530273,0.48800086975097656,103.18175506591797
5,FROM,binary,1,10000,15.804499626159668,15.337499618530273,0.46700000762939453,103.0448226928711
6,FROM,binary,1,10000,15.891500473022461,15.337499618530273,0.5540008544921875,103.61206817626953
0,TO,binary,1,10000,13.309999465942383,13.309999465942383,0.0,100.0
1,TO,binary,1,10000,13.848999977111816,13.309999465942383,0.5390005111694336,104.04959106445312
2,TO,binary,1,10000,14.044500350952148,13.309999465942383,0.7345008850097656,105.5184097290039
3,TO,binary,1,10000,13.981499671936035,13.309999465942383,0.6715002059936523,105.04508209228516
4,TO,binary,1,10000,13.983499526977539,13.309999465942383,0.6735000610351562,105.06010437011719
5,TO,binary,1,10000,13.862499237060547,13.309999465942383,0.5524997711181641,104.15100860595703
6,TO,binary,1,10000,13.961000442504883,13.309999465942383,0.6510009765625,104.89105987548828
0,FROM,binary,1,100000,19.95599937438965,19.95599937438965,0.0,100.0
1,FROM,binary,1,100000,20.364999771118164,19.95599937438965,0.4090003967285156,102.04950714111328
2,FROM,binary,1,100000,20.496000289916992,19.95599937438965,0.5400009155273438,102.7059555053711
3,FROM,binary,1,100000,20.496999740600586,19.95599937438965,0.5410003662109375,102.7109603881836
4,FROM,binary,1,100000,20.67300033569336,19.95599937438965,0.7170009613037109,103.59291076660156
5,FROM,binary,1,100000,20.25200080871582,19.95599937438965,0.2960014343261719,101.4832763671875
6,FROM,binary,1,100000,20.18600082397461,19.95599937438965,0.23000144958496094,101.15254211425781
0,TO,binary,1,100000,21.538000106811523,21.538000106811523,0.0,100.0
1,TO,binary,1,100000,21.92300033569336,21.538000106811523,0.38500022888183594,101.78754425048828
2,TO,binary,1,100000,22.19300079345703,21.538000106811523,0.6550006866455078,103.0411376953125
3,TO,binary,1,100000,22.125999450683594,21.538000106811523,0.5879993438720703,102.73005676269531
4,TO,binary,1,100000,22.257999420166016,21.538000106811523,0.7199993133544922,103.34292602539062
5,TO,binary,1,100000,21.96299934387207,21.538000106811523,0.4249992370605469,101.97325134277344
6,TO,binary,1,100000,22.010000228881836,21.538000106811523,0.4720001220703125,102.19147491455078
0,FROM,binary,1,1000000,64.23400115966797,64.23400115966797,0.0,100.0
1,FROM,binary,1,1000000,66.41899871826172,64.23400115966797,2.18499755859375,103.40162658691406
2,FROM,binary,1,1000000,65.13200378417969,64.23400115966797,0.8980026245117188,101.39801788330078
3,FROM,binary,1,1000000,65.2969970703125,64.23400115966797,1.0629959106445312,101.65487670898438
4,FROM,binary,1,1000000,64.21700286865234,64.23400115966797,-0.016998291015625,99.9735336303711
5,FROM,binary,1,1000000,63.80799865722656,64.23400115966797,-0.42600250244140625,99.33679962158203
6,FROM,binary,1,1000000,63.63600158691406,64.23400115966797,-0.5979995727539062,99.06903076171875
0,TO,binary,1,1000000,99.63800048828125,99.63800048828125,0.0,100.0
1,TO,binary,1,1000000,100.5270004272461,99.63800048828125,0.8889999389648438,100.8922348022461
2,TO,binary,1,1000000,101.05799865722656,99.63800048828125,1.4199981689453125,101.42515563964844
3,TO,binary,1,1000000,100.7229995727539,99.63800048828125,1.0849990844726562,101.08894348144531
4,TO,binary,1,1000000,102.45899963378906,99.63800048828125,2.8209991455078125,102.83124542236328
5,TO,binary,1,1000000,100.55000305175781,99.63800048828125,0.9120025634765625,100.91531372070312
6,TO,binary,1,1000000,101.74600219726562,99.63800048828125,2.108001708984375,102.11565399169922
0,FROM,binary,10,10,12.640999794006348,12.640999794006348,0.0,100.0
1,FROM,binary,10,10,13.130000114440918,12.640999794006348,0.4890003204345703,103.86836242675781
2,FROM,binary,10,10,13.579000473022461,12.640999794006348,0.9380006790161133,107.42030334472656
3,FROM,binary,10,10,13.29699993133545,12.640999794006348,0.6560001373291016,105.18946838378906
4,FROM,binary,10,10,13.289999961853027,12.640999794006348,0.6490001678466797,105.13409423828125
5,FROM,binary,10,10,13.277000427246094,12.640999794006348,0.6360006332397461,105.03125
6,FROM,binary,10,10,13.27299976348877,12.640999794006348,0.6319999694824219,104.99960327148438
0,TO,binary,10,10,12.565999984741211,12.565999984741211,0.0,100.0
1,TO,binary,10,10,12.913999557495117,12.565999984741211,0.34799957275390625,102.76937866210938
2,TO,binary,10,10,13.359999656677246,12.565999984741211,0.7939996719360352,106.31864166259766
3,TO,binary,10,10,13.015999794006348,12.565999984741211,0.4499998092651367,103.58109283447266
4,TO,binary,10,10,13.057999610900879,12.565999984741211,0.49199962615966797,103.91532135009766
5,TO,binary,10,10,13.020000457763672,12.565999984741211,0.45400047302246094,103.61292266845703
6,TO,binary,10,10,13.017000198364258,12.565999984741211,0.4510002136230469,103.58904266357422
0,FROM,binary,10,100,12.86299991607666,12.86299991607666,0.0,100.0
1,FROM,binary,10,100,13.32800006866455,12.86299991607666,0.4650001525878906,103.61502075195312
2,FROM,binary,10,100,13.526000022888184,12.86299991607666,0.6630001068115234,105.15432739257812
3,FROM,binary,10,100,13.470000267028809,12.86299991607666,0.6070003509521484,104.71895599365234
4,FROM,binary,10,100,13.343000411987305,12.86299991607666,0.48000049591064453,103.73162841796875
5,FROM,binary,10,100,13.369999885559082,12.86299991607666,0.5069999694824219,103.94153594970703
6,FROM,binary,10,100,13.567999839782715,12.86299991607666,0.7049999237060547,105.4808349609375
0,TO,binary,10,100,12.529000282287598,12.529000282287598,0.0,100.0
1,TO,binary,10,100,12.916000366210938,12.529000282287598,0.38700008392333984,103.08882904052734
2,TO,binary,10,100,13.373000144958496,12.529000282287598,0.8439998626708984,106.73637390136719
3,TO,binary,10,100,13.062999725341797,12.529000282287598,0.5339994430541992,104.26210021972656
4,TO,binary,10,100,13.003000259399414,12.529000282287598,0.4739999771118164,103.7832260131836
5,TO,binary,10,100,13.067000389099121,12.529000282287598,0.5380001068115234,104.29403686523438
6,TO,binary,10,100,13.043999671936035,12.529000282287598,0.5149993896484375,104.11045837402344
0,FROM,binary,10,1000,15.017999649047852,15.017999649047852,0.0,100.0
1,FROM,binary,10,1000,15.529000282287598,15.017999649047852,0.5110006332397461,103.402587890625
2,FROM,binary,10,1000,15.595999717712402,15.017999649047852,0.5780000686645508,103.84871673583984
3,FROM,binary,10,1000,15.640999794006348,15.017999649047852,0.6230001449584961,104.14835357666016
4,FROM,binary,10,1000,15.510000228881836,15.017999649047852,0.4920005798339844,103.27607727050781
5,FROM,binary,10,1000,15.482000350952148,15.017999649047852,0.4640007019042969,103.08963012695312
6,FROM,binary,10,1000,15.517000198364258,15.017999649047852,0.49900054931640625,103.32268524169922
0,TO,binary,10,1000,12.866999626159668,12.866999626159668,0.0,100.0
1,TO,binary,10,1000,13.407999992370605,12.866999626159668,0.5410003662109375,104.20455932617188
2,TO,binary,10,1000,13.616999626159668,12.866999626159668,0.75,105.82887268066406
3,TO,binary,10,1000,13.378999710083008,12.866999626159668,0.5120000839233398,103.97917175292969
4,TO,binary,10,1000,13.24899959564209,12.866999626159668,0.3819999694824219,102.96883392333984
5,TO,binary,10,1000,13.305999755859375,12.866999626159668,0.43900012969970703,103.41182708740234
6,TO,binary,10,1000,13.39799976348877,12.866999626159668,0.5310001373291016,104.1268310546875
0,FROM,binary,10,10000,16.547000885009766,16.547000885009766,0.0,100.0
1,FROM,binary,10,10000,17.19499969482422,16.547000885009766,0.6479988098144531,103.91610717773438
2,FROM,binary,10,10000,17.28350067138672,16.547000885009766,0.7364997863769531,104.4509506225586
3,FROM,binary,10,10000,17.154998779296875,16.547000885009766,0.6079978942871094,103.67436218261719
4,FROM,binary,10,10000,17.150501251220703,16.547000885009766,0.6035003662109375,103.64718627929688
5,FROM,binary,10,10000,17.0935001373291,16.547000885009766,0.5464992523193359,103.30270385742188
6,FROM,binary,10,10000,17.18600082397461,16.547000885009766,0.6389999389648438,103.86172485351562
0,TO,binary,10,10000,15.735000610351562,15.735000610351562,0.0,100.0
1,TO,binary,10,10000,16.07550048828125,15.735000610351562,0.3404998779296875,102.16397094726562
2,TO,binary,10,10000,16.29800033569336,15.735000610351562,0.5629997253417969,103.57801055908203
3,TO,binary,10,10000,16.23550033569336,15.735000610351562,0.5004997253417969,103.18080139160156
4,TO,binary,10,10000,16.247499465942383,15.735000610351562,0.5124988555908203,103.2570571899414
5,TO,binary,10,10000,16.095001220703125,15.735000610351562,0.3600006103515625,102.28790283203125
6,TO,binary,10,10000,16.145999908447266,15.735000610351562,0.4109992980957031,102.61200714111328
0,FROM,binary,10,100000,32.57600021362305,32.57600021362305,0.0,100.0
1,FROM,binary,10,100000,33.95100021362305,32.57600021362305,1.375,104.22090148925781
2,FROM,binary,10,100000,33.14799880981445,32.57600021362305,0.5719985961914062,101.75588989257812
3,FROM,binary,10,100000,33.06800079345703,32.57600021362305,0.4920005798339844,101.51030731201172
4,FROM,binary,10,100000,32.861000061035156,32.57600021362305,0.2849998474121094,100.8748779296875
5,FROM,binary,10,100000,32.80799865722656,32.57600021362305,0.23199844360351562,100.7121810913086
6,FROM,binary,10,100000,32.89500045776367,32.57600021362305,0.319000244140625,100.979248046875
0,TO,binary,10,100000,43.58000183105469,43.58000183105469,0.0,100.0
1,TO,binary,10,100000,44.15299987792969,43.58000183105469,0.572998046875,101.3148193359375
2,TO,binary,10,100000,44.14899826049805,43.58000183105469,0.5689964294433594,101.3056411743164
3,TO,binary,10,100000,44.42399978637695,43.58000183105469,0.8439979553222656,101.93666076660156
4,TO,binary,10,100000,44.382999420166016,43.58000183105469,0.8029975891113281,101.84258270263672
5,TO,binary,10,100000,44.492000579833984,43.58000183105469,0.9119987487792969,102.09269714355469
6,TO,binary,10,100000,44.71799850463867,43.58000183105469,1.1379966735839844,102.61128234863281
0,FROM,binary,10,1000000,186.5019989013672,186.5019989013672,0.0,100.0
1,FROM,binary,10,1000000,197.38299560546875,186.5019989013672,10.880996704101562,105.83425903320312
2,FROM,binary,10,1000000,187.1199951171875,186.5019989013672,0.6179962158203125,100.33136749267578
3,FROM,binary,10,1000000,188.21400451660156,186.5019989013672,1.712005615234375,100.91796112060547
4,FROM,binary,10,1000000,187.4929962158203,186.5019989013672,0.990997314453125,100.53136444091797
5,FROM,binary,10,1000000,187.08599853515625,186.5019989013672,0.5839996337890625,100.31314086914062
6,FROM,binary,10,1000000,187.656005859375,186.5019989013672,1.1540069580078125,100.61876678466797
0,TO,binary,10,1000000,319.75,319.75,0.0,100.0
1,TO,binary,10,1000000,321.6669921875,319.75,1.9169921875,100.59952545166016
2,TO,binary,10,1000000,322.052001953125,319.75,2.302001953125,100.71994018554688
3,TO,binary,10,1000000,323.9429931640625,319.75,4.1929931640625,101.31134033203125
4,TO,binary,10,1000000,324.718994140625,319.75,4.968994140625,101.55402374267578
5,TO,binary,10,1000000,324.9989929199219,319.75,5.248992919921875,101.64159393310547
6,TO,binary,10,1000000,328.3080139160156,319.75,8.558013916015625,102.67647552490234
0,FROM,binary,100,10,12.881999969482422,12.881999969482422,0.0,100.0
1,FROM,binary,100,10,13.335000038146973,12.881999969482422,0.4530000686645508,103.51653289794922
2,FROM,binary,100,10,13.489999771118164,12.881999969482422,0.6079998016357422,104.71975708007812
3,FROM,binary,100,10,13.45199966430664,12.881999969482422,0.5699996948242188,104.42477416992188
4,FROM,binary,100,10,13.340999603271484,12.881999969482422,0.4589996337890625,103.56310272216797
5,FROM,binary,100,10,13.406000137329102,12.881999969482422,0.5240001678466797,104.06769561767578
6,FROM,binary,100,10,13.329999923706055,12.881999969482422,0.4479999542236328,103.47771453857422
0,TO,binary,100,10,12.597999572753906,12.597999572753906,0.0,100.0
1,TO,binary,100,10,13.069999694824219,12.597999572753906,0.4720001220703125,103.74662780761719
2,TO,binary,100,10,13.001999855041504,12.597999572753906,0.40400028228759766,103.20686340332031
3,TO,binary,100,10,13.168999671936035,12.597999572753906,0.5710000991821289,104.532470703125
4,TO,binary,100,10,12.972000122070312,12.597999572753906,0.37400054931640625,102.9687271118164
5,TO,binary,100,10,13.152000427246094,12.597999572753906,0.5540008544921875,104.39753723144531
6,TO,binary,100,10,13.086000442504883,12.597999572753906,0.48800086975097656,103.8736343383789
0,FROM,binary,100,100,13.017999649047852,13.017999649047852,0.0,100.0
1,FROM,binary,100,100,13.569000244140625,13.017999649047852,0.5510005950927734,104.23261260986328
2,FROM,binary,100,100,13.67300033569336,13.017999649047852,0.6550006866455078,105.03150177001953
3,FROM,binary,100,100,13.630999565124512,13.017999649047852,0.6129999160766602,104.7088623046875
4,FROM,binary,100,100,13.74899959564209,13.017999649047852,0.7309999465942383,105.61530303955078
5,FROM,binary,100,100,13.654000282287598,13.017999649047852,0.6360006332397461,104.88554382324219
6,FROM,binary,100,100,13.727999687194824,13.017999649047852,0.7100000381469727,105.45399475097656
0,TO,binary,100,100,12.723999977111816,12.723999977111816,0.0,100.0
1,TO,binary,100,100,13.194000244140625,12.723999977111816,0.4700002670288086,103.69380950927734
2,TO,binary,100,100,13.270000457763672,12.723999977111816,0.5460004806518555,104.29110717773438
3,TO,binary,100,100,13.204999923706055,12.723999977111816,0.4809999465942383,103.78025817871094
4,TO,binary,100,100,13.324999809265137,12.723999977111816,0.6009998321533203,104.72335815429688
5,TO,binary,100,100,13.225000381469727,12.723999977111816,0.5010004043579102,103.93744659423828
6,TO,binary,100,100,13.305000305175781,12.723999977111816,0.5810003280639648,104.56617736816406
0,FROM,binary,100,1000,17.047000885009766,17.047000885009766,0.0,100.0
1,FROM,binary,100,1000,17.31599998474121,17.047000885009766,0.2689990997314453,101.57798767089844
2,FROM,binary,100,1000,17.17799949645996,17.047000885009766,0.1309986114501953,100.7684555053711
3,FROM,binary,100,1000,17.214000701904297,17.047000885009766,0.16699981689453125,100.9796371459961
4,FROM,binary,100,1000,17.232999801635742,17.047000885009766,0.18599891662597656,101.09109497070312
5,FROM,binary,100,1000,17.292999267578125,17.047000885009766,0.24599838256835938,101.44306182861328
6,FROM,binary,100,1000,17.191999435424805,17.047000885009766,0.14499855041503906,100.8505859375
0,TO,binary,100,1000,15.074000358581543,15.074000358581543,0.0,100.0
1,TO,binary,100,1000,15.357000350952148,15.074000358581543,0.28299999237060547,101.87740325927734
2,TO,binary,100,1000,15.225000381469727,15.074000358581543,0.1510000228881836,101.00172424316406
3,TO,binary,100,1000,15.368000030517578,15.074000358581543,0.29399967193603516,101.95037078857422
4,TO,binary,100,1000,15.196999549865723,15.074000358581543,0.12299919128417969,100.81596374511719
5,TO,binary,100,1000,15.281000137329102,15.074000358581543,0.2069997787475586,101.37322235107422
6,TO,binary,100,1000,15.343999862670898,15.074000358581543,0.26999950408935547,101.79115295410156
0,FROM,binary,100,10000,29.73349952697754,29.73349952697754,0.0,100.0
1,FROM,binary,100,10000,31.118999481201172,29.73349952697754,1.3854999542236328,104.65972137451172
2,FROM,binary,100,10000,29.923999786376953,29.73349952697754,0.19050025939941406,100.64069366455078
3,FROM,binary,100,10000,30.078998565673828,29.73349952697754,0.34549903869628906,101.16197967529297
4,FROM,binary,100,10000,30.03499984741211,29.73349952697754,0.3015003204345703,101.01400756835938
5,FROM,binary,100,10000,29.95199966430664,29.73349952697754,0.21850013732910156,100.73486328125
6,FROM,binary,100,10000,30.002500534057617,29.73349952697754,0.2690010070800781,100.90470123291016
0,TO,binary,100,10000,35.260498046875,35.260498046875,0.0,100.0
1,TO,binary,100,10000,35.204498291015625,35.260498046875,-0.055999755859375,99.8411865234375
2,TO,binary,100,10000,35.233001708984375,35.260498046875,-0.027496337890625,99.9220199584961
3,TO,binary,100,10000,35.316001892089844,35.260498046875,0.05550384521484375,100.15741729736328
4,TO,binary,100,10000,35.24250030517578,35.260498046875,-0.01799774169921875,99.94895935058594
5,TO,binary,100,10000,35.38999938964844,35.260498046875,0.1295013427734375,100.36727142333984
6,TO,binary,100,10000,35.71050262451172,35.260498046875,0.45000457763671875,101.27622985839844
0,FROM,binary,100,100000,154.0070037841797,154.0070037841797,0.0,100.0
1,FROM,binary,100,100000,165.68499755859375,154.0070037841797,11.677993774414062,107.58277130126953
2,FROM,binary,100,100000,154.49000549316406,154.0070037841797,0.483001708984375,100.31362915039062
3,FROM,binary,100,100000,154.74099731445312,154.0070037841797,0.7339935302734375,100.47660064697266
4,FROM,binary,100,100000,154.70700073242188,154.0070037841797,0.6999969482421875,100.45452117919922
5,FROM,binary,100,100000,155.13400268554688,154.0070037841797,1.1269989013671875,100.7317886352539
6,FROM,binary,100,100000,156.11900329589844,154.0070037841797,2.11199951171875,101.37136840820312
0,TO,binary,100,100000,234.7899932861328,234.7899932861328,0.0,100.0
1,TO,binary,100,100000,234.13900756835938,234.7899932861328,-0.6509857177734375,99.72274017333984
2,TO,binary,100,100000,234.6269989013672,234.7899932861328,-0.162994384765625,99.93058013916016
3,TO,binary,100,100000,236.39700317382812,234.7899932861328,1.6070098876953125,100.68444061279297
4,TO,binary,100,100000,235.70700073242188,234.7899932861328,0.9170074462890625,100.39056396484375
5,TO,binary,100,100000,237.71800231933594,234.7899932861328,2.928009033203125,101.2470703125
6,TO,binary,100,100000,241.58099365234375,234.7899932861328,6.7910003662109375,102.89237213134766
0,FROM,binary,100,1000000,1393.68798828125,1393.68798828125,0.0,100.0
1,FROM,binary,100,1000000,1508.93994140625,1393.68798828125,115.251953125,108.26956939697266
2,FROM,binary,100,1000000,1397.9730224609375,1393.68798828125,4.2850341796875,100.30746459960938
3,FROM,binary,100,1000000,1410.2230224609375,1393.68798828125,16.5350341796875,101.18641662597656
4,FROM,binary,100,1000000,1401.7869873046875,1393.68798828125,8.0989990234375,100.58112335205078
5,FROM,binary,100,1000000,1405.2840576171875,1393.68798828125,11.5960693359375,100.83204650878906
6,FROM,binary,100,1000000,1412.89794921875,1393.68798828125,19.2099609375,101.37835693359375
0,TO,binary,100,1000000,2215.431884765625,2215.431884765625,0.0,100.0
1,TO,binary,100,1000000,2197.257080078125,2215.431884765625,-18.1748046875,99.17962646484375
2,TO,binary,100,1000000,2213.698974609375,2215.431884765625,-1.73291015625,99.92178344726562
3,TO,binary,100,1000000,2225.531982421875,2215.431884765625,10.10009765625,100.45589447021484
4,TO,binary,100,1000000,2219.27392578125,2215.431884765625,3.842041015625,100.17342376708984
5,TO,binary,100,1000000,2239.72900390625,2215.431884765625,24.297119140625,101.09672546386719
6,TO,binary,100,1000000,2218.947998046875,2215.431884765625,3.51611328125,100.1587142944336
0,FROM,csv,1,10,13.560999870300293,13.560999870300293,0.0,100.0
1,FROM,csv,1,10,13.218999862670898,13.560999870300293,-0.34200000762939453,97.47806549072266
2,FROM,csv,1,10,13.222000122070312,13.560999870300293,-0.33899974822998047,97.50019073486328
3,FROM,csv,1,10,13.279999732971191,13.560999870300293,-0.28100013732910156,97.9278793334961
4,FROM,csv,1,10,13.373000144958496,13.560999870300293,-0.18799972534179688,98.6136703491211
5,FROM,csv,1,10,13.354000091552734,13.560999870300293,-0.2069997787475586,98.47356414794922
6,FROM,csv,1,10,13.33899974822998,13.560999870300293,-0.2220001220703125,98.36295318603516
0,TO,csv,1,10,13.848999977111816,13.848999977111816,0.0,100.0
1,TO,csv,1,10,13.024999618530273,13.848999977111816,-0.824000358581543,94.05010986328125
2,TO,csv,1,10,13.036999702453613,13.848999977111816,-0.8120002746582031,94.13675689697266
3,TO,csv,1,10,13.055999755859375,13.848999977111816,-0.7930002212524414,94.27395629882812
4,TO,csv,1,10,13.026000022888184,13.848999977111816,-0.8229999542236328,94.05733489990234
5,TO,csv,1,10,12.987000465393066,13.848999977111816,-0.86199951171875,93.77572631835938
6,TO,csv,1,10,13.098999977111816,13.848999977111816,-0.75,94.5844497680664
0,FROM,csv,1,100,13.854999542236328,13.854999542236328,0.0,100.0
1,FROM,csv,1,100,13.319000244140625,13.854999542236328,-0.5359992980957031,96.13136291503906
2,FROM,csv,1,100,13.371999740600586,13.854999542236328,-0.4829998016357422,96.51390075683594
3,FROM,csv,1,100,13.465999603271484,13.854999542236328,-0.38899993896484375,97.19234466552734
4,FROM,csv,1,100,13.354999542236328,13.854999542236328,-0.5,96.39119720458984
5,FROM,csv,1,100,13.343999862670898,13.854999542236328,-0.5109996795654297,96.31179809570312
6,FROM,csv,1,100,13.437999725341797,13.854999542236328,-0.41699981689453125,96.9902572631836
0,TO,csv,1,100,13.986000061035156,13.986000061035156,0.0,100.0
1,TO,csv,1,100,12.9399995803833,13.986000061035156,-1.0460004806518555,92.52108764648438
2,TO,csv,1,100,13.222999572753906,13.986000061035156,-0.76300048828125,94.54454040527344
3,TO,csv,1,100,13.085000038146973,13.986000061035156,-0.9010000228881836,93.5578384399414
4,TO,csv,1,100,12.944000244140625,13.986000061035156,-1.0419998168945312,92.54969024658203
5,TO,csv,1,100,13.029000282287598,13.986000061035156,-0.9569997787475586,93.1574478149414
6,TO,csv,1,100,13.107999801635742,13.986000061035156,-0.8780002593994141,93.7222900390625
0,FROM,csv,1,1000,16.31399917602539,16.31399917602539,0.0,100.0
1,FROM,csv,1,1000,15.364999771118164,16.31399917602539,-0.9489994049072266,94.18291473388672
2,FROM,csv,1,1000,15.6899995803833,16.31399917602539,-0.6239995956420898,96.1750717163086
3,FROM,csv,1,1000,15.498000144958496,16.31399917602539,-0.8159990310668945,94.9981689453125
4,FROM,csv,1,1000,15.472000122070312,16.31399917602539,-0.8419990539550781,94.83879089355469
5,FROM,csv,1,1000,15.456000328063965,16.31399917602539,-0.8579988479614258,94.74071502685547
6,FROM,csv,1,1000,15.541000366210938,16.31399917602539,-0.7729988098144531,95.26174926757812
0,TO,csv,1,1000,13.993000030517578,13.993000030517578,0.0,100.0
1,TO,csv,1,1000,13.029000282287598,13.993000030517578,-0.9639997482299805,93.11083984375
2,TO,csv,1,1000,13.005000114440918,13.993000030517578,-0.9879999160766602,92.9393310546875
3,TO,csv,1,1000,13.029000282287598,13.993000030517578,-0.9639997482299805,93.11083984375
4,TO,csv,1,1000,13.093999862670898,13.993000030517578,-0.8990001678466797,93.57535552978516
5,TO,csv,1,1000,13.065999984741211,13.993000030517578,-0.9270000457763672,93.37525939941406
6,TO,csv,1,1000,13.16100025177002,13.993000030517578,-0.8319997787475586,94.0541763305664
0,FROM,csv,1,10000,16.613500595092773,16.613500595092773,0.0,100.0
1,FROM,csv,1,10000,15.991000175476074,16.613500595092773,-0.6225004196166992,96.25304412841797
2,FROM,csv,1,10000,16.041500091552734,16.613500595092773,-0.5720005035400391,96.55701446533203
3,FROM,csv,1,10000,15.98449993133545,16.613500595092773,-0.6290006637573242,96.21392059326172
4,FROM,csv,1,10000,16.121999740600586,16.613500595092773,-0.4915008544921875,97.04155731201172
5,FROM,csv,1,10000,15.991000175476074,16.613500595092773,-0.6225004196166992,96.25304412841797
6,FROM,csv,1,10000,16.129499435424805,16.613500595092773,-0.48400115966796875,97.08670043945312
0,TO,csv,1,10000,14.781999588012695,14.781999588012695,0.0,100.0
1,TO,csv,1,10000,13.803999900817871,14.781999588012695,-0.9779996871948242,93.38385009765625
2,TO,csv,1,10000,13.908500671386719,14.781999588012695,-0.8734989166259766,94.0907974243164
3,TO,csv,1,10000,13.904000282287598,14.781999588012695,-0.8779993057250977,94.06034851074219
4,TO,csv,1,10000,13.939499855041504,14.781999588012695,-0.8424997329711914,94.30049896240234
5,TO,csv,1,10000,13.883500099182129,14.781999588012695,-0.8984994888305664,93.92166900634766
6,TO,csv,1,10000,14.010000228881836,14.781999588012695,-0.7719993591308594,94.77743530273438
0,FROM,csv,1,100000,21.482999801635742,21.482999801635742,0.0,100.0
1,FROM,csv,1,100000,21.386999130249023,21.482999801635742,-0.09600067138671875,99.55313110351562
2,FROM,csv,1,100000,21.916000366210938,21.482999801635742,0.4330005645751953,102.01555633544922
3,FROM,csv,1,100000,22.04199981689453,21.482999801635742,0.5590000152587891,102.60205078125
4,FROM,csv,1,100000,21.575000762939453,21.482999801635742,0.09200096130371094,100.4282455444336
5,FROM,csv,1,100000,21.57200050354004,21.482999801635742,0.08900070190429688,100.41429138183594
6,FROM,csv,1,100000,21.663000106811523,21.482999801635742,0.18000030517578125,100.83787536621094
0,TO,csv,1,100000,21.7189998626709,21.7189998626709,0.0,100.0
1,TO,csv,1,100000,21.691999435424805,21.7189998626709,-0.02700042724609375,99.87567901611328
2,TO,csv,1,100000,21.95400047302246,21.7189998626709,0.2350006103515625,101.08200073242188
3,TO,csv,1,100000,21.81599998474121,21.7189998626709,0.0970001220703125,100.44661712646484
4,TO,csv,1,100000,22.030000686645508,21.7189998626709,0.3110008239746094,101.43193054199219
5,TO,csv,1,100000,21.884000778198242,21.7189998626709,0.16500091552734375,100.75971221923828
6,TO,csv,1,100000,21.983999252319336,21.7189998626709,0.2649993896484375,101.22013092041016
0,FROM,csv,1,1000000,76.99800109863281,76.99800109863281,0.0,100.0
1,FROM,csv,1,1000000,77.22599792480469,76.99800109863281,0.227996826171875,100.29610443115234
2,FROM,csv,1,1000000,79.01100158691406,76.99800109863281,2.01300048828125,102.6143569946289
3,FROM,csv,1,1000000,81.03299713134766,76.99800109863281,4.034996032714844,105.24039459228516
4,FROM,csv,1,1000000,78.05899810791016,76.99800109863281,1.0609970092773438,101.3779525756836
5,FROM,csv,1,1000000,77.69000244140625,76.99800109863281,0.6920013427734375,100.89872741699219
6,FROM,csv,1,1000000,77.74800109863281,76.99800109863281,0.75,100.97404479980469
0,TO,csv,1,1000000,97.697998046875,97.697998046875,0.0,100.0
1,TO,csv,1,1000000,98.20899963378906,97.697998046875,0.5110015869140625,100.52304077148438
2,TO,csv,1,1000000,98.28500366210938,97.697998046875,0.587005615234375,100.60083770751953
3,TO,csv,1,1000000,98.16000366210938,97.697998046875,0.462005615234375,100.47289276123047
4,TO,csv,1,1000000,100.19400024414062,97.697998046875,2.496002197265625,102.5548095703125
5,TO,csv,1,1000000,97.94200134277344,97.697998046875,0.2440032958984375,100.249755859375
6,TO,csv,1,1000000,98.08300018310547,97.697998046875,0.38500213623046875,100.39407348632812
0,FROM,csv,10,10,13.324000358581543,13.324000358581543,0.0,100.0
1,FROM,csv,10,10,13.21399974822998,13.324000358581543,-0.1100006103515625,99.1744155883789
2,FROM,csv,10,10,13.309000015258789,13.324000358581543,-0.015000343322753906,99.88742065429688
3,FROM,csv,10,10,13.317999839782715,13.324000358581543,-0.006000518798828125,99.95496368408203
4,FROM,csv,10,10,13.371000289916992,13.324000358581543,0.04699993133544922,100.35275268554688
5,FROM,csv,10,10,13.244000434875488,13.324000358581543,-0.07999992370605469,99.39958190917969
6,FROM,csv,10,10,13.317999839782715,13.324000358581543,-0.006000518798828125,99.95496368408203
0,TO,csv,10,10,12.859999656677246,12.859999656677246,0.0,100.0
1,TO,csv,10,10,12.932000160217285,12.859999656677246,0.07200050354003906,100.55987548828125
2,TO,csv,10,10,13.168000221252441,12.859999656677246,0.3080005645751953,102.39501953125
3,TO,csv,10,10,13.026000022888184,12.859999656677246,0.1660003662109375,101.29082489013672
4,TO,csv,10,10,13.197999954223633,12.859999656677246,0.3380002975463867,102.62830352783203
5,TO,csv,10,10,12.968999862670898,12.859999656677246,0.10900020599365234,100.84758758544922
6,TO,csv,10,10,13.07699966430664,12.859999656677246,0.21700000762939453,101.68740844726562
0,FROM,csv,10,100,12.819999694824219,12.819999694824219,0.0,100.0
1,FROM,csv,10,100,13.432000160217285,12.819999694824219,0.6120004653930664,104.77379608154297
2,FROM,csv,10,100,13.395999908447266,12.819999694824219,0.5760002136230469,104.49298858642578
3,FROM,csv,10,100,13.501999855041504,12.819999694824219,0.6820001602172852,105.31980895996094
4,FROM,csv,10,100,13.49899959564209,12.819999694824219,0.6789999008178711,105.2964096069336
5,FROM,csv,10,100,13.420000076293945,12.819999694824219,0.6000003814697266,104.68019104003906
6,FROM,csv,10,100,13.489999771118164,12.819999694824219,0.6700000762939453,105.22620391845703
0,TO,csv,10,100,12.5,12.5,0.0,100.0
1,TO,csv,10,100,12.918000221252441,12.5,0.4180002212524414,103.34400177001953
2,TO,csv,10,100,13.345000267028809,12.5,0.8450002670288086,106.76000213623047
3,TO,csv,10,100,13.027000427246094,12.5,0.5270004272460938,104.21600341796875
4,TO,csv,10,100,13.081999778747559,12.5,0.5819997787475586,104.65599060058594
5,TO,csv,10,100,13.0600004196167,12.5,0.5600004196166992,104.4800033569336
6,TO,csv,10,100,13.157999992370605,12.5,0.6579999923706055,105.26399230957031
0,FROM,csv,10,1000,15.651000022888184,15.651000022888184,0.0,100.0
1,FROM,csv,10,1000,15.5600004196167,15.651000022888184,-0.09099960327148438,99.41857147216797
2,FROM,csv,10,1000,15.680000305175781,15.651000022888184,0.029000282287597656,100.185302734375
3,FROM,csv,10,1000,15.850000381469727,15.651000022888184,0.19900035858154297,101.271484375
4,FROM,csv,10,1000,15.729000091552734,15.651000022888184,0.07800006866455078,100.49836730957031
5,FROM,csv,10,1000,15.72599983215332,15.651000022888184,0.07499980926513672,100.47919464111328
6,FROM,csv,10,1000,15.67300033569336,15.651000022888184,0.02200031280517578,100.14057159423828
0,TO,csv,10,1000,12.970000267028809,12.970000267028809,0.0,100.0
1,TO,csv,10,1000,13.168999671936035,12.970000267028809,0.19899940490722656,101.53430938720703
2,TO,csv,10,1000,13.329999923706055,12.970000267028809,0.3599996566772461,102.775634765625
3,TO,csv,10,1000,13.196999549865723,12.970000267028809,0.22699928283691406,101.75018310546875
4,TO,csv,10,1000,13.229000091552734,12.970000267028809,0.2589998245239258,101.99691009521484
5,TO,csv,10,1000,13.406000137329102,12.970000267028809,0.43599987030029297,103.36160278320312
6,TO,csv,10,1000,13.324999809265137,12.970000267028809,0.3549995422363281,102.7370834350586
0,FROM,csv,10,10000,17.426000595092773,17.426000595092773,0.0,100.0
1,FROM,csv,10,10000,17.561500549316406,17.426000595092773,0.1354999542236328,100.77758026123047
2,FROM,csv,10,10000,17.750999450683594,17.426000595092773,0.3249988555908203,101.86502075195312
3,FROM,csv,10,10000,17.808000564575195,17.426000595092773,0.3819999694824219,102.19213104248047
4,FROM,csv,10,10000,17.74850082397461,17.426000595092773,0.32250022888183594,101.8506851196289
5,FROM,csv,10,10000,17.739999771118164,17.426000595092773,0.3139991760253906,101.80189514160156
6,FROM,csv,10,10000,17.812999725341797,17.426000595092773,0.38699913024902344,102.22080993652344
0,TO,csv,10,10000,15.305000305175781,15.305000305175781,0.0,100.0
1,TO,csv,10,10000,15.382999420166016,15.305000305175781,0.07799911499023438,100.50962829589844
2,TO,csv,10,10000,15.480499267578125,15.305000305175781,0.17549896240234375,101.14667510986328
3,TO,csv,10,10000,15.523500442504883,15.305000305175781,0.21850013732910156,101.4276351928711
4,TO,csv,10,10000,15.47450065612793,15.305000305175781,0.16950035095214844,101.10747528076172
5,TO,csv,10,10000,15.467500686645508,15.305000305175781,0.16250038146972656,101.06175231933594
6,TO,csv,10,10000,15.567500114440918,15.305000305175781,0.2624998092651367,101.71512603759766
0,FROM,csv,10,100000,37.650001525878906,37.650001525878906,0.0,100.0
1,FROM,csv,10,100000,37.683998107910156,37.650001525878906,0.03399658203125,100.09030151367188
2,FROM,csv,10,100000,38.185001373291016,37.650001525878906,0.5349998474121094,101.42098999023438
3,FROM,csv,10,100000,38.141998291015625,37.650001525878906,0.49199676513671875,101.3067626953125
4,FROM,csv,10,100000,37.9010009765625,37.650001525878906,0.25099945068359375,100.66666412353516
5,FROM,csv,10,100000,37.880001068115234,37.650001525878906,0.22999954223632812,100.61088562011719
6,FROM,csv,10,100000,37.957000732421875,37.650001525878906,0.30699920654296875,100.8154067993164
0,TO,csv,10,100000,38.176998138427734,38.176998138427734,0.0,100.0
1,TO,csv,10,100000,37.303001403808594,38.176998138427734,-0.8739967346191406,97.7106704711914
2,TO,csv,10,100000,38.12799835205078,38.176998138427734,-0.048999786376953125,99.87165069580078
3,TO,csv,10,100000,37.50400161743164,38.176998138427734,-0.6729965209960938,98.23716735839844
4,TO,csv,10,100000,37.77899932861328,38.176998138427734,-0.3979988098144531,98.95748901367188
5,TO,csv,10,100000,37.57500076293945,38.176998138427734,-0.6019973754882812,98.42314147949219
6,TO,csv,10,100000,37.76499938964844,38.176998138427734,-0.4119987487792969,98.92082214355469
0,FROM,csv,10,1000000,236.43299865722656,236.43299865722656,0.0,100.0
1,FROM,csv,10,1000000,237.48599243164062,236.43299865722656,1.0529937744140625,100.44536590576172
2,FROM,csv,10,1000000,239.64199829101562,236.43299865722656,3.2089996337890625,101.35725402832031
3,FROM,csv,10,1000000,239.6540069580078,236.43299865722656,3.22100830078125,101.36233520507812
4,FROM,csv,10,1000000,239.29600524902344,236.43299865722656,2.863006591796875,101.2109146118164
5,FROM,csv,10,1000000,237.58200073242188,236.43299865722656,1.1490020751953125,100.48596954345703
6,FROM,csv,10,1000000,239.42799377441406,236.43299865722656,2.9949951171875,101.26673889160156
0,TO,csv,10,1000000,255.21200561523438,255.21200561523438,0.0,100.0
1,TO,csv,10,1000000,252.9550018310547,255.21200561523438,-2.2570037841796875,99.11563110351562
2,TO,csv,10,1000000,253.76400756835938,255.21200561523438,-1.447998046875,99.43263244628906
3,TO,csv,10,1000000,255.51400756835938,255.21200561523438,0.302001953125,100.11833953857422
4,TO,csv,10,1000000,258.44500732421875,255.21200561523438,3.233001708984375,101.26679229736328
5,TO,csv,10,1000000,256.885009765625,255.21200561523438,1.673004150390625,100.65553283691406
6,TO,csv,10,1000000,259.4280090332031,255.21200561523438,4.21600341796875,101.65196990966797
0,FROM,csv,100,10,12.902000427246094,12.902000427246094,0.0,100.0
1,FROM,csv,100,10,13.22700023651123,12.902000427246094,0.3249998092651367,102.51898956298828
2,FROM,csv,100,10,13.375,12.902000427246094,0.47299957275390625,103.66609191894531
3,FROM,csv,100,10,13.463000297546387,12.902000427246094,0.560999870300293,104.34815979003906
4,FROM,csv,100,10,13.394000053405762,12.902000427246094,0.49199962615966797,103.81336212158203
5,FROM,csv,100,10,13.45300006866455,12.902000427246094,0.550999641418457,104.27064514160156
6,FROM,csv,100,10,13.50100040435791,12.902000427246094,0.5989999771118164,104.64269256591797
0,TO,csv,100,10,12.682999610900879,12.682999610900879,0.0,100.0
1,TO,csv,100,10,12.970000267028809,12.682999610900879,0.2870006561279297,102.26287841796875
2,TO,csv,100,10,13.180000305175781,12.682999610900879,0.49700069427490234,103.91863250732422
3,TO,csv,100,10,13.170999526977539,12.682999610900879,0.48799991607666016,103.84767150878906
4,TO,csv,100,10,13.0600004196167,12.682999610900879,0.3770008087158203,102.97248077392578
5,TO,csv,100,10,13.081999778747559,12.682999610900879,0.3990001678466797,103.14594268798828
6,TO,csv,100,10,13.062999725341797,12.682999610900879,0.38000011444091797,102.99613189697266
0,FROM,csv,100,100,13.586999893188477,13.586999893188477,0.0,100.0
1,FROM,csv,100,100,13.616000175476074,13.586999893188477,0.029000282287597656,100.21344757080078
2,FROM,csv,100,100,14.178000450134277,13.586999893188477,0.5910005569458008,104.34974670410156
3,FROM,csv,100,100,13.664999961853027,13.586999893188477,0.07800006866455078,100.5740737915039
4,FROM,csv,100,100,13.621999740600586,13.586999893188477,0.034999847412109375,100.25759887695312
5,FROM,csv,100,100,13.717000007629395,13.586999893188477,0.13000011444091797,100.95679473876953
6,FROM,csv,100,100,13.784000396728516,13.586999893188477,0.19700050354003906,101.44992065429688
0,TO,csv,100,100,13.39799976348877,13.39799976348877,0.0,100.0
1,TO,csv,100,100,13.204000473022461,13.39799976348877,-0.1939992904663086,98.55203247070312
2,TO,csv,100,100,13.190999984741211,13.39799976348877,-0.2069997787475586,98.45499420166016
3,TO,csv,100,100,13.204000473022461,13.39799976348877,-0.1939992904663086,98.55203247070312
4,TO,csv,100,100,13.25,13.39799976348877,-0.14799976348876953,98.89535522460938
5,TO,csv,100,100,13.149999618530273,13.39799976348877,-0.2480001449584961,98.14897918701172
6,TO,csv,100,100,13.241999626159668,13.39799976348877,-0.15600013732910156,98.83564758300781
0,FROM,csv,100,1000,15.279999732971191,15.279999732971191,0.0,100.0
1,FROM,csv,100,1000,15.805999755859375,15.279999732971191,0.5260000228881836,103.4424057006836
2,FROM,csv,100,1000,16.04599952697754,15.279999732971191,0.7659997940063477,105.0130844116211
3,FROM,csv,100,1000,15.991000175476074,15.279999732971191,0.7110004425048828,104.65314483642578
4,FROM,csv,100,1000,15.918999671936035,15.279999732971191,0.6389999389648438,104.18193054199219
5,FROM,csv,100,1000,15.87600040435791,15.279999732971191,0.5960006713867188,103.90052795410156
6,FROM,csv,100,1000,15.906999588012695,15.279999732971191,0.6269998550415039,104.10340118408203
0,TO,csv,100,1000,14.236000061035156,14.236000061035156,0.0,100.0
1,TO,csv,100,1000,14.675999641418457,14.236000061035156,0.4399995803833008,103.09075164794922
2,TO,csv,100,1000,14.890000343322754,14.236000061035156,0.6540002822875977,104.593994140625
3,TO,csv,100,1000,14.763999938964844,14.236000061035156,0.5279998779296875,103.70890808105469
4,TO,csv,100,1000,14.722999572753906,14.236000061035156,0.48699951171875,103.4208984375
5,TO,csv,100,1000,14.934000015258789,14.236000061035156,0.6979999542236328,104.90306854248047
6,TO,csv,100,1000,14.887999534606934,14.236000061035156,0.6519994735717773,104.57994079589844
0,FROM,csv,100,10000,33.08650207519531,33.08650207519531,0.0,100.0
1,FROM,csv,100,10000,33.58000183105469,33.08650207519531,0.493499755859375,101.49154663085938
2,FROM,csv,100,10000,33.87950134277344,33.08650207519531,0.792999267578125,102.3967514038086
3,FROM,csv,100,10000,33.85749816894531,33.08650207519531,0.77099609375,102.33024597167969
4,FROM,csv,100,10000,33.76499938964844,33.08650207519531,0.678497314453125,102.05067443847656
5,FROM,csv,100,10000,33.66649627685547,33.08650207519531,0.5799942016601562,101.75296020507812
6,FROM,csv,100,10000,33.82099914550781,33.08650207519531,0.7344970703125,102.21992492675781
0,TO,csv,100,10000,30.456501007080078,30.456501007080078,0.0,100.0
1,TO,csv,100,10000,30.464000701904297,30.456501007080078,0.00749969482421875,100.02462768554688
2,TO,csv,100,10000,30.704999923706055,30.456501007080078,0.24849891662597656,100.81591796875
3,TO,csv,100,10000,30.626998901367188,30.456501007080078,0.17049789428710938,100.55980682373047
4,TO,csv,100,10000,30.60300064086914,30.456501007080078,0.1464996337890625,100.48101043701172
5,TO,csv,100,10000,30.798500061035156,30.456501007080078,0.3419990539550781,101.12291717529297
6,TO,csv,100,10000,30.898500442504883,30.456501007080078,0.4419994354248047,101.45125579833984
0,FROM,csv,100,100000,208.33599853515625,208.33599853515625,0.0,100.0
1,FROM,csv,100,100000,210.4040069580078,208.33599853515625,2.0680084228515625,100.99263000488281
2,FROM,csv,100,100000,212.66799926757812,208.33599853515625,4.332000732421875,102.07933044433594
3,FROM,csv,100,100000,210.90699768066406,208.33599853515625,2.5709991455078125,101.23406982421875
4,FROM,csv,100,100000,212.05099487304688,208.33599853515625,3.714996337890625,101.7831802368164
5,FROM,csv,100,100000,210.51100158691406,208.33599853515625,2.1750030517578125,101.04399108886719
6,FROM,csv,100,100000,211.79299926757812,208.33599853515625,3.457000732421875,101.65933227539062
0,TO,csv,100,100000,188.36099243164062,188.36099243164062,0.0,100.0
1,TO,csv,100,100000,187.0030059814453,188.36099243164062,-1.3579864501953125,99.279052734375
2,TO,csv,100,100000,188.2740020751953,188.36099243164062,-0.0869903564453125,99.95381927490234
3,TO,csv,100,100000,188.9530029296875,188.36099243164062,0.592010498046875,100.31429290771484
4,TO,csv,100,100000,189.08299255371094,188.36099243164062,0.7220001220703125,100.38330841064453
5,TO,csv,100,100000,191.50999450683594,188.36099243164062,3.1490020751953125,101.67179107666016
6,TO,csv,100,100000,192.5469970703125,188.36099243164062,4.186004638671875,102.22233581542969
0,FROM,csv,100,1000000,1958.012939453125,1958.012939453125,0.0,100.0
1,FROM,csv,100,1000000,1977.29296875,1958.012939453125,19.280029296875,100.98466491699219
2,FROM,csv,100,1000000,2006.8919677734375,1958.012939453125,48.8790283203125,102.4963607788086
3,FROM,csv,100,1000000,1988.43896484375,1958.012939453125,30.426025390625,101.5539321899414
4,FROM,csv,100,1000000,1986.2769775390625,1958.012939453125,28.2640380859375,101.4435043334961
5,FROM,csv,100,1000000,1973.31298828125,1958.012939453125,15.300048828125,100.78140258789062
6,FROM,csv,100,1000000,1986.18701171875,1958.012939453125,28.174072265625,101.43891906738281
0,TO,csv,100,1000000,1753.8360595703125,1753.8360595703125,0.0,100.0
1,TO,csv,100,1000000,1731.0150146484375,1753.8360595703125,-22.821044921875,98.69879150390625
2,TO,csv,100,1000000,1755.260986328125,1753.8360595703125,1.4249267578125,100.08123779296875
3,TO,csv,100,1000000,1757.8260498046875,1753.8360595703125,3.989990234375,100.22750091552734
4,TO,csv,100,1000000,1759.4930419921875,1753.8360595703125,5.656982421875,100.32254791259766
5,TO,csv,100,1000000,1767.1669921875,1753.8360595703125,13.3309326171875,100.76010131835938
6,TO,csv,100,1000000,1765.3909912109375,1753.8360595703125,11.554931640625,100.6588363647461
0,FROM,text,1,10,13.883000373840332,13.883000373840332,0.0,100.0
1,FROM,text,1,10,14.142999649047852,13.883000373840332,0.25999927520751953,101.87278747558594
2,FROM,text,1,10,14.241999626159668,13.883000373840332,0.35899925231933594,102.58589172363281
3,FROM,text,1,10,14.255999565124512,13.883000373840332,0.3729991912841797,102.68673706054688
4,FROM,text,1,10,14.144000053405762,13.883000373840332,0.2609996795654297,101.87998962402344
5,FROM,text,1,10,14.373000144958496,13.883000373840332,0.48999977111816406,103.52948760986328
6,FROM,text,1,10,14.133999824523926,13.883000373840332,0.25099945068359375,101.8079605102539
0,TO,text,1,10,17.40399932861328,17.40399932861328,0.0,100.0
1,TO,text,1,10,13.90999984741211,17.40399932861328,-3.493999481201172,79.92416381835938
2,TO,text,1,10,14.065999984741211,17.40399932861328,-3.3379993438720703,80.82050323486328
3,TO,text,1,10,14.190999984741211,17.40399932861328,-3.2129993438720703,81.53873443603516
4,TO,text,1,10,13.897000312805176,17.40399932861328,-3.5069990158081055,79.8494644165039
5,TO,text,1,10,14.057000160217285,17.40399932861328,-3.346999168395996,80.76879119873047
6,TO,text,1,10,13.890000343322754,17.40399932861328,-3.5139989852905273,79.80924224853516
0,FROM,text,1,100,14.071000099182129,14.071000099182129,0.0,100.0
1,FROM,text,1,100,14.333999633789062,14.071000099182129,0.2629995346069336,101.86909484863281
2,FROM,text,1,100,14.138999938964844,14.071000099182129,0.06799983978271484,100.48326110839844
3,FROM,text,1,100,14.378999710083008,14.071000099182129,0.3079996109008789,102.18889617919922
4,FROM,text,1,100,14.293999671936035,14.071000099182129,0.22299957275390625,101.5848159790039
5,FROM,text,1,100,13.947999954223633,14.071000099182129,-0.1230001449584961,99.12586212158203
6,FROM,text,1,100,13.640999794006348,14.071000099182129,-0.43000030517578125,96.9440689086914
0,TO,text,1,100,14.019000053405762,14.019000053405762,0.0,100.0
1,TO,text,1,100,13.812999725341797,14.019000053405762,-0.20600032806396484,98.53056335449219
2,TO,text,1,100,13.782999992370605,14.019000053405762,-0.23600006103515625,98.31656646728516
3,TO,text,1,100,14.086999893188477,14.019000053405762,0.06799983978271484,100.48505401611328
4,TO,text,1,100,13.91100025177002,14.019000053405762,-0.10799980163574219,99.2296142578125
5,TO,text,1,100,13.98799991607666,14.019000053405762,-0.031000137329101562,99.77886962890625
6,TO,text,1,100,13.555000305175781,14.019000053405762,-0.46399974822998047,96.6902084350586
0,FROM,text,1,1000,15.567000389099121,15.567000389099121,0.0,100.0
1,FROM,text,1,1000,15.062999725341797,15.567000389099121,-0.5040006637573242,96.76237487792969
2,FROM,text,1,1000,16.465999603271484,15.567000389099121,0.8989992141723633,105.77503204345703
3,FROM,text,1,1000,15.805000305175781,15.567000389099121,0.23799991607666016,101.52886962890625
4,FROM,text,1,1000,16.367000579833984,15.567000389099121,0.8000001907348633,105.13907623291016
5,FROM,text,1,1000,15.442000389099121,15.567000389099121,-0.125,99.197021484375
6,FROM,text,1,1000,16.18600082397461,15.567000389099121,0.6190004348754883,103.97635650634766
0,TO,text,1,1000,12.66100025177002,12.66100025177002,0.0,100.0
1,TO,text,1,1000,13.74899959564209,12.66100025177002,1.0879993438720703,108.59330749511719
2,TO,text,1,1000,13.866999626159668,12.66100025177002,1.2059993743896484,109.52531433105469
3,TO,text,1,1000,13.95199966430664,12.66100025177002,1.290999412536621,110.19666290283203
4,TO,text,1,1000,13.446999549865723,12.66100025177002,0.7859992980957031,106.20803833007812
5,TO,text,1,1000,13.871000289916992,12.66100025177002,1.2100000381469727,109.55690002441406
6,TO,text,1,1000,12.772000312805176,12.66100025177002,0.11100006103515625,100.876708984375
0,FROM,text,1,10000,16.38450050354004,16.38450050354004,0.0,100.0
1,FROM,text,1,10000,15.923999786376953,16.38450050354004,-0.46050071716308594,97.18941497802734
2,FROM,text,1,10000,16.492000579833984,16.38450050354004,0.10750007629394531,100.6561050415039
3,FROM,text,1,10000,16.13450050354004,16.38450050354004,-0.25,98.47416687011719
4,FROM,text,1,10000,15.76200008392334,16.38450050354004,-0.6225004196166992,96.20067596435547
5,FROM,text,1,10000,16.323501586914062,16.38450050354004,-0.06099891662597656,99.62770080566406
6,FROM,text,1,10000,16.945499420166016,16.38450050354004,0.5609989166259766,103.42396545410156
0,TO,text,1,10000,14.073999404907227,14.073999404907227,0.0,100.0
1,TO,text,1,10000,13.622499465942383,14.073999404907227,-0.45149993896484375,96.79196166992188
2,TO,text,1,10000,14.510499954223633,14.073999404907227,0.43650054931640625,103.10147094726562
3,TO,text,1,10000,13.808000564575195,14.073999404907227,-0.26599884033203125,98.10999298095703
4,TO,text,1,10000,14.184499740600586,14.073999404907227,0.11050033569335938,100.7851333618164
5,TO,text,1,10000,14.276500701904297,14.073999404907227,0.2025012969970703,101.43883514404297
6,TO,text,1,10000,14.656999588012695,14.073999404907227,0.5830001831054688,104.14239501953125
0,FROM,text,1,100000,22.018999099731445,22.018999099731445,0.0,100.0
1,FROM,text,1,100000,22.065000534057617,22.018999099731445,0.046001434326171875,100.20891571044922
2,FROM,text,1,100000,24.642000198364258,22.018999099731445,2.6230010986328125,111.91244506835938
3,FROM,text,1,100000,22.64900016784668,22.018999099731445,0.6300010681152344,102.86116790771484
4,FROM,text,1,100000,21.961000442504883,22.018999099731445,-0.0579986572265625,99.7365951538086
5,FROM,text,1,100000,22.131999969482422,22.018999099731445,0.11300086975097656,100.51319885253906
6,FROM,text,1,100000,22.611000061035156,22.018999099731445,0.5920009613037109,102.68858337402344
0,TO,text,1,100000,21.6560001373291,21.6560001373291,0.0,100.0
1,TO,text,1,100000,21.54199981689453,21.6560001373291,-0.11400032043457031,99.47358703613281
2,TO,text,1,100000,21.19099998474121,21.6560001373291,-0.4650001525878906,97.85279083251953
3,TO,text,1,100000,21.726999282836914,21.6560001373291,0.0709991455078125,100.32785034179688
4,TO,text,1,100000,21.058000564575195,21.6560001373291,-0.5979995727539062,97.23863983154297
5,TO,text,1,100000,21.110000610351562,21.6560001373291,-0.5459995269775391,97.478759765625
6,TO,text,1,100000,22.076000213623047,21.6560001373291,0.4200000762939453,101.93941497802734
0,FROM,text,1,1000000,77.44200134277344,77.44200134277344,0.0,100.0
1,FROM,text,1,1000000,77.62799835205078,77.44200134277344,0.18599700927734375,100.24017333984375
2,FROM,text,1,1000000,78.61499786376953,77.44200134277344,1.1729965209960938,101.5146713256836
3,FROM,text,1,1000000,79.97699737548828,77.44200134277344,2.5349960327148438,103.2734146118164
4,FROM,text,1,1000000,77.64700317382812,77.44200134277344,0.2050018310546875,100.26471710205078
5,FROM,text,1,1000000,78.54499816894531,77.44200134277344,1.102996826171875,101.42428588867188
6,FROM,text,1,1000000,77.41000366210938,77.44200134277344,-0.0319976806640625,99.95867919921875
0,TO,text,1,1000000,92.9489974975586,92.9489974975586,0.0,100.0
1,TO,text,1,1000000,93.47100067138672,92.9489974975586,0.522003173828125,100.56160736083984
2,TO,text,1,1000000,92.6520004272461,92.9489974975586,-0.2969970703125,99.68047332763672
3,TO,text,1,1000000,93.25599670410156,92.9489974975586,0.30699920654296875,100.33029174804688
4,TO,text,1,1000000,94.66100311279297,92.9489974975586,1.712005615234375,101.84188079833984
5,TO,text,1,1000000,92.94200134277344,92.9489974975586,-0.00699615478515625,99.99246978759766
6,TO,text,1,1000000,94.03800201416016,92.9489974975586,1.0890045166015625,101.17161560058594
0,FROM,text,10,10,13.668000221252441,13.668000221252441,0.0,100.0
1,FROM,text,10,10,14.230999946594238,13.668000221252441,0.5629997253417969,104.11911010742188
2,FROM,text,10,10,14.213000297546387,13.668000221252441,0.5450000762939453,103.98741912841797
3,FROM,text,10,10,14.206999778747559,13.668000221252441,0.5389995574951172,103.94351196289062
4,FROM,text,10,10,14.178000450134277,13.668000221252441,0.5100002288818359,103.7313461303711
5,FROM,text,10,10,14.168000221252441,13.668000221252441,0.5,103.65817260742188
6,FROM,text,10,10,13.041000366210938,13.668000221252441,-0.6269998550415039,95.41264343261719
0,TO,text,10,10,13.258000373840332,13.258000373840332,0.0,100.0
1,TO,text,10,10,14.015000343322754,13.258000373840332,0.7569999694824219,105.70975494384766
2,TO,text,10,10,13.857000350952148,13.258000373840332,0.5989999771118164,104.51803588867188
3,TO,text,10,10,14.130000114440918,13.258000373840332,0.8719997406005859,106.57715606689453
4,TO,text,10,10,13.675000190734863,13.258000373840332,0.41699981689453125,103.145263671875
5,TO,text,10,10,13.873000144958496,13.258000373840332,0.6149997711181641,104.63871002197266
6,TO,text,10,10,12.642999649047852,13.258000373840332,-0.6150007247924805,95.36128997802734
0,FROM,text,10,100,14.029000282287598,14.029000282287598,0.0,100.0
1,FROM,text,10,100,12.913999557495117,14.029000282287598,-1.1150007247924805,92.05216979980469
2,FROM,text,10,100,14.333000183105469,14.029000282287598,0.3039999008178711,102.16693878173828
3,FROM,text,10,100,14.196999549865723,14.029000282287598,0.167999267578125,101.19751739501953
4,FROM,text,10,100,14.414999961853027,14.029000282287598,0.3859996795654297,102.75144958496094
5,FROM,text,10,100,14.237000465393066,14.029000282287598,0.20800018310546875,101.4826431274414
6,FROM,text,10,100,13.413000106811523,14.029000282287598,-0.6160001754760742,95.60909271240234
0,TO,text,10,100,13.739999771118164,13.739999771118164,0.0,100.0
1,TO,text,10,100,13.039999961853027,13.739999771118164,-0.6999998092651367,94.90538787841797
2,TO,text,10,100,14.35200023651123,13.739999771118164,0.6120004653930664,104.45414733886719
3,TO,text,10,100,14.057999610900879,13.739999771118164,0.31799983978271484,102.31441497802734
4,TO,text,10,100,13.869999885559082,13.739999771118164,0.13000011444091797,100.94613647460938
5,TO,text,10,100,13.954000473022461,13.739999771118164,0.21400070190429688,101.55750274658203
6,TO,text,10,100,12.6850004196167,13.739999771118164,-1.0549993515014648,92.32169342041016
0,FROM,text,10,1000,16.42300033569336,16.42300033569336,0.0,100.0
1,FROM,text,10,1000,15.159000396728516,16.42300033569336,-1.2639999389648438,92.30348205566406
2,FROM,text,10,1000,16.437999725341797,16.42300033569336,0.0149993896484375,100.09132385253906
3,FROM,text,10,1000,15.28499984741211,16.42300033569336,-1.13800048828125,93.07069396972656
4,FROM,text,10,1000,15.720999717712402,16.42300033569336,-0.702000617980957,95.72550201416016
5,FROM,text,10,1000,15.319999694824219,16.42300033569336,-1.1030006408691406,93.28380584716797
6,FROM,text,10,1000,15.371000289916992,16.42300033569336,-1.0520000457763672,93.59434509277344
0,TO,text,10,1000,13.982000350952148,13.982000350952148,0.0,100.0
1,TO,text,10,1000,12.71399974822998,13.982000350952148,-1.268000602722168,90.93119812011719
2,TO,text,10,1000,13.946999549865723,13.982000350952148,-0.03500080108642578,99.74967193603516
3,TO,text,10,1000,12.883000373840332,13.982000350952148,-1.0989999771118164,92.139892578125
4,TO,text,10,1000,14.104999542236328,13.982000350952148,0.12299919128417969,100.87969207763672
5,TO,text,10,1000,13.88700008392334,13.982000350952148,-0.0950002670288086,99.320556640625
6,TO,text,10,1000,12.871000289916992,13.982000350952148,-1.1110000610351562,92.05406951904297
0,FROM,text,10,10000,18.152999877929688,18.152999877929688,0.0,100.0
1,FROM,text,10,10000,17.071998596191406,18.152999877929688,-1.0810012817382812,94.04505157470703
2,FROM,text,10,10000,17.866500854492188,18.152999877929688,-0.2864990234375,98.4217529296875
3,FROM,text,10,10000,17.2135009765625,18.152999877929688,-0.9394989013671875,94.82455444335938
4,FROM,text,10,10000,17.117000579833984,18.152999877929688,-1.0359992980957031,94.29295349121094
5,FROM,text,10,10000,17.16550064086914,18.152999877929688,-0.9874992370605469,94.56013488769531
6,FROM,text,10,10000,17.24850082397461,18.152999877929688,-0.9044990539550781,95.0173568725586
0,TO,text,10,10000,15.850500106811523,15.850500106811523,0.0,100.0
1,TO,text,10,10000,14.83799934387207,15.850500106811523,-1.0125007629394531,93.6121826171875
2,TO,text,10,10000,15.73799991607666,15.850500106811523,-0.11250019073486328,99.29023742675781
3,TO,text,10,10000,14.84850025177002,15.850500106811523,-1.001999855041504,93.67843627929688
4,TO,text,10,10000,14.962499618530273,15.850500106811523,-0.88800048828125,94.39765167236328
5,TO,text,10,10000,14.853500366210938,15.850500106811523,-0.9969997406005859,93.7099838256836
6,TO,text,10,10000,14.980500221252441,15.850500106811523,-0.869999885559082,94.51121520996094
0,FROM,text,10,100000,35.8650016784668,35.8650016784668,0.0,100.0
1,FROM,text,10,100000,34.875,35.8650016784668,-0.9900016784667969,97.2396469116211
2,FROM,text,10,100000,35.0880012512207,35.8650016784668,-0.7770004272460938,97.83354187011719
3,FROM,text,10,100000,35.084999084472656,35.8650016784668,-0.7800025939941406,97.8251724243164
4,FROM,text,10,100000,34.96699905395508,35.8650016784668,-0.8980026245117188,97.49615478515625
5,FROM,text,10,100000,35.28900146484375,35.8650016784668,-0.5760002136230469,98.39397430419922
6,FROM,text,10,100000,35.305999755859375,35.8650016784668,-0.5590019226074219,98.44137573242188
0,TO,text,10,100000,34.76599884033203,34.76599884033203,0.0,100.0
1,TO,text,10,100000,33.784000396728516,34.76599884033203,-0.9819984436035156,97.17540740966797
2,TO,text,10,100000,34.32500076293945,34.76599884033203,-0.4409980773925781,98.73152160644531
3,TO,text,10,100000,34.09600067138672,34.76599884033203,-0.6699981689453125,98.07283020019531
4,TO,text,10,100000,34.02799987792969,34.76599884033203,-0.7379989624023438,97.87724304199219
5,TO,text,10,100000,34.06800079345703,34.76599884033203,-0.697998046875,97.99229431152344
6,TO,text,10,100000,33.952999114990234,34.76599884033203,-0.8129997253417969,97.66150665283203
0,FROM,text,10,1000000,213.9080047607422,213.9080047607422,0.0,100.0
1,FROM,text,10,1000000,211.656005859375,213.9080047607422,-2.2519989013671875,98.94721221923828
2,FROM,text,10,1000000,210.56500244140625,213.9080047607422,-3.3430023193359375,98.43717956542969
3,FROM,text,10,1000000,212.63499450683594,213.9080047607422,-1.27301025390625,99.40487670898438
4,FROM,text,10,1000000,211.08299255371094,213.9080047607422,-2.82501220703125,98.67933654785156
5,FROM,text,10,1000000,211.6999969482422,213.9080047607422,-2.2080078125,98.96778106689453
6,FROM,text,10,1000000,213.35499572753906,213.9080047607422,-0.553009033203125,99.74147033691406
0,TO,text,10,1000000,222.84500122070312,222.84500122070312,0.0,100.0
1,TO,text,10,1000000,220.36399841308594,222.84500122070312,-2.4810028076171875,98.88666534423828
2,TO,text,10,1000000,220.44400024414062,222.84500122070312,-2.4010009765625,98.92256927490234
3,TO,text,10,1000000,221.60699462890625,222.84500122070312,-1.238006591796875,99.4444580078125
4,TO,text,10,1000000,223.49000549316406,222.84500122070312,0.6450042724609375,100.28944396972656
5,TO,text,10,1000000,222.03399658203125,222.84500122070312,-0.811004638671875,99.63606262207031
6,TO,text,10,1000000,223.54299926757812,222.84500122070312,0.697998046875,100.31322479248047
0,FROM,text,100,10,13.892999649047852,13.892999649047852,0.0,100.0
1,FROM,text,100,10,13.324999809265137,13.892999649047852,-0.5679998397827148,95.91161346435547
2,FROM,text,100,10,13.640000343322754,13.892999649047852,-0.25299930572509766,98.17893981933594
3,FROM,text,100,10,13.666000366210938,13.892999649047852,-0.22699928283691406,98.3660888671875
4,FROM,text,100,10,13.510000228881836,13.892999649047852,-0.3829994201660156,97.24321746826172
5,FROM,text,100,10,13.572999954223633,13.892999649047852,-0.31999969482421875,97.69668579101562
6,FROM,text,100,10,13.590999603271484,13.892999649047852,-0.3020000457763672,97.82624053955078
0,TO,text,100,10,13.597999572753906,13.597999572753906,0.0,100.0
1,TO,text,100,10,13.107999801635742,13.597999572753906,-0.48999977111816406,96.39653015136719
2,TO,text,100,10,13.63700008392334,13.597999572753906,0.039000511169433594,100.28680419921875
3,TO,text,100,10,13.458000183105469,13.597999572753906,-0.1399993896484375,98.97044372558594
4,TO,text,100,10,12.836999893188477,13.597999572753906,-0.7609996795654297,94.4035873413086
5,TO,text,100,10,13.442999839782715,13.597999572753906,-0.1549997329711914,98.8601303100586
6,TO,text,100,10,13.145000457763672,13.597999572753906,-0.4529991149902344,96.66864013671875
0,FROM,text,100,100,14.270999908447266,14.270999908447266,0.0,100.0
1,FROM,text,100,100,13.690999984741211,14.270999908447266,-0.5799999237060547,95.9358139038086
2,FROM,text,100,100,13.954000473022461,14.270999908447266,-0.3169994354248047,97.77871704101562
3,FROM,text,100,100,13.734000205993652,14.270999908447266,-0.5369997024536133,96.23712921142578
4,FROM,text,100,100,13.774999618530273,14.270999908447266,-0.4960002899169922,96.5244140625
5,FROM,text,100,100,13.798999786376953,14.270999908447266,-0.4720001220703125,96.69258880615234
6,FROM,text,100,100,13.779000282287598,14.270999908447266,-0.49199962615966797,96.55245208740234
0,TO,text,100,100,13.916000366210938,13.916000366210938,0.0,100.0
1,TO,text,100,100,13.135000228881836,13.916000366210938,-0.7810001373291016,94.38774871826172
2,TO,text,100,100,13.37600040435791,13.916000366210938,-0.5399999618530273,96.11957550048828
3,TO,text,100,100,13.236000061035156,13.916000366210938,-0.6800003051757812,95.11353302001953
4,TO,text,100,100,13.397000312805176,13.916000366210938,-0.5190000534057617,96.27047729492188
5,TO,text,100,100,13.451000213623047,13.916000366210938,-0.4650001525878906,96.65852355957031
6,TO,text,100,100,13.281999588012695,13.916000366210938,-0.6340007781982422,95.444091796875
0,FROM,text,100,1000,16.301000595092773,16.301000595092773,0.0,100.0
1,FROM,text,100,1000,15.444000244140625,16.301000595092773,-0.8570003509521484,94.7426528930664
2,FROM,text,100,1000,15.586999893188477,16.301000595092773,-0.7140007019042969,95.6198959350586
3,FROM,text,100,1000,15.524999618530273,16.301000595092773,-0.7760009765625,95.23954772949219
4,FROM,text,100,1000,15.562000274658203,16.301000595092773,-0.7390003204345703,95.46653747558594
5,FROM,text,100,1000,15.576000213623047,16.301000595092773,-0.7250003814697266,95.55242156982422
6,FROM,text,100,1000,15.61400032043457,16.301000595092773,-0.6870002746582031,95.78553771972656
0,TO,text,100,1000,15.484999656677246,15.484999656677246,0.0,100.0
1,TO,text,100,1000,14.47599983215332,15.484999656677246,-1.0089998245239258,93.48402404785156
2,TO,text,100,1000,14.781000137329102,15.484999656677246,-0.7039995193481445,95.45366668701172
3,TO,text,100,1000,14.555999755859375,15.484999656677246,-0.9289999008178711,94.00064086914062
4,TO,text,100,1000,14.604000091552734,15.484999656677246,-0.8809995651245117,94.31062316894531
5,TO,text,100,1000,14.49899959564209,15.484999656677246,-0.9860000610351562,93.6325454711914
6,TO,text,100,1000,14.621000289916992,15.484999656677246,-0.8639993667602539,94.42041015625
0,FROM,text,100,10000,30.19700050354004,30.19700050354004,0.0,100.0
1,FROM,text,100,10000,29.7450008392334,30.19700050354004,-0.4519996643066406,98.50316619873047
2,FROM,text,100,10000,29.91200065612793,30.19700050354004,-0.2849998474121094,99.05619812011719
3,FROM,text,100,10000,29.762001037597656,30.19700050354004,-0.4349994659423828,98.55946350097656
4,FROM,text,100,10000,29.80699920654297,30.19700050354004,-0.3900012969970703,98.7084732055664
5,FROM,text,100,10000,29.83599853515625,30.19700050354004,-0.36100196838378906,98.80451202392578
6,FROM,text,100,10000,29.899499893188477,30.19700050354004,-0.2975006103515625,99.01480102539062
0,TO,text,100,10000,28.44900131225586,28.44900131225586,0.0,100.0
1,TO,text,100,10000,27.70349884033203,28.44900131225586,-0.7455024719238281,97.37950897216797
2,TO,text,100,10000,27.892000198364258,28.44900131225586,-0.5570011138916016,98.04210662841797
3,TO,text,100,10000,27.894500732421875,28.44900131225586,-0.5545005798339844,98.05089569091797
4,TO,text,100,10000,27.784500122070312,28.44900131225586,-0.6645011901855469,97.66423797607422
5,TO,text,100,10000,27.776500701904297,28.44900131225586,-0.6725006103515625,97.63612365722656
6,TO,text,100,10000,27.82349967956543,28.44900131225586,-0.6255016326904297,97.80132293701172
0,FROM,text,100,100000,173.20399475097656,173.20399475097656,0.0,100.0
1,FROM,text,100,100000,171.4409942626953,173.20399475097656,-1.76300048828125,98.98212432861328
2,FROM,text,100,100000,170.9149932861328,173.20399475097656,-2.28900146484375,98.67843627929688
3,FROM,text,100,100000,171.31399536132812,173.20399475097656,-1.8899993896484375,98.90879821777344
4,FROM,text,100,100000,171.24099731445312,173.20399475097656,-1.9629974365234375,98.86665344238281
5,FROM,text,100,100000,171.21299743652344,173.20399475097656,-1.990997314453125,98.8504867553711
6,FROM,text,100,100000,171.2259979248047,173.20399475097656,-1.977996826171875,98.85799407958984
0,TO,text,100,100000,158.9290008544922,158.9290008544922,0.0,100.0
1,TO,text,100,100000,158.33399963378906,158.9290008544922,-0.595001220703125,99.62561798095703
2,TO,text,100,100000,158.60499572753906,158.9290008544922,-0.324005126953125,99.79613494873047
3,TO,text,100,100000,159.40199279785156,158.9290008544922,0.472991943359375,100.29761505126953
4,TO,text,100,100000,159.76600646972656,158.9290008544922,0.837005615234375,100.52665710449219
5,TO,text,100,100000,159.83299255371094,158.9290008544922,0.90399169921875,100.56880950927734
6,TO,text,100,100000,160.59300231933594,158.9290008544922,1.66400146484375,101.04701232910156
0,FROM,text,100,1000000,1588.3929443359375,1588.3929443359375,0.0,100.0
1,FROM,text,100,1000000,1581.6839599609375,1588.3929443359375,-6.708984375,99.57762145996094
2,FROM,text,100,1000000,1576.9520263671875,1588.3929443359375,-11.44091796875,99.27971649169922
3,FROM,text,100,1000000,1580.1280517578125,1588.3929443359375,-8.264892578125,99.47966766357422
4,FROM,text,100,1000000,1579.989990234375,1588.3929443359375,-8.4029541015625,99.47097778320312
5,FROM,text,100,1000000,1579.9580078125,1588.3929443359375,-8.4349365234375,99.46896362304688
6,FROM,text,100,1000000,1582.1610107421875,1588.3929443359375,-6.23193359375,99.60765838623047
0,TO,text,100,1000000,1445.23095703125,1445.23095703125,0.0,100.0
1,TO,text,100,1000000,1450.217041015625,1445.23095703125,4.986083984375,100.34500122070312
2,TO,text,100,1000000,1453.0579833984375,1445.23095703125,7.8270263671875,100.54158020019531
3,TO,text,100,1000000,1465.68896484375,1445.23095703125,20.4580078125,101.4155502319336
4,TO,text,100,1000000,1466.9520263671875,1445.23095703125,21.7210693359375,101.50294494628906
5,TO,text,100,1000000,1457.7099609375,1445.23095703125,12.47900390625,100.86345672607422
6,TO,text,100,1000000,1456.1710205078125,1445.23095703125,10.9400634765625,100.7569808959961
version,type,format,n_columns,n_rows,runtime,base_runtime,diff_runtime,diff_percentage
0,FROM,binary,1,10,13.380999565124512,13.380999565124512,0.0,100.0
1,FROM,binary,1,10,13.300000190734863,13.380999565124512,-0.08099937438964844,99.39466857910156
2,FROM,binary,1,10,13.399999618530273,13.380999565124512,0.01900005340576172,100.1419906616211
3,FROM,binary,1,10,13.25100040435791,13.380999565124512,-0.12999916076660156,99.02848052978516
4,FROM,binary,1,10,13.274999618530273,13.380999565124512,-0.10599994659423828,99.20783233642578
5,FROM,binary,1,10,13.302000045776367,13.380999565124512,-0.07899951934814453,99.40961456298828
6,FROM,binary,1,10,13.223999977111816,13.380999565124512,-0.1569995880126953,98.82669830322266
0,TO,binary,1,10,13.083999633789062,13.083999633789062,0.0,100.0
1,TO,binary,1,10,13.095000267028809,13.083999633789062,0.011000633239746094,100.08407592773438
2,TO,binary,1,10,13.0,13.083999633789062,-0.0839996337890625,99.35800170898438
3,TO,binary,1,10,13.071000099182129,13.083999633789062,-0.012999534606933594,99.90064239501953
4,TO,binary,1,10,13.02299976348877,13.083999633789062,-0.06099987030029297,99.53378295898438
5,TO,binary,1,10,13.149999618530273,13.083999633789062,0.06599998474121094,100.50443267822266
6,TO,binary,1,10,13.015000343322754,13.083999633789062,-0.0689992904663086,99.47264099121094
0,FROM,binary,1,100,13.458999633789062,13.458999633789062,0.0,100.0
1,FROM,binary,1,100,13.39900016784668,13.458999633789062,-0.05999946594238281,99.55420684814453
2,FROM,binary,1,100,13.39900016784668,13.458999633789062,-0.05999946594238281,99.55420684814453
3,FROM,binary,1,100,13.38700008392334,13.458999633789062,-0.07199954986572266,99.46504211425781
4,FROM,binary,1,100,13.498000144958496,13.458999633789062,0.039000511169433594,100.2897720336914
5,FROM,binary,1,100,13.470000267028809,13.458999633789062,0.011000633239746094,100.08172607421875
6,FROM,binary,1,100,13.720999717712402,13.458999633789062,0.26200008392333984,101.9466552734375
0,TO,binary,1,100,13.020999908447266,13.020999908447266,0.0,100.0
1,TO,binary,1,100,13.086999893188477,13.020999908447266,0.06599998474121094,100.50688171386719
2,TO,binary,1,100,13.04699993133545,13.020999908447266,0.026000022888183594,100.19967651367188
3,TO,binary,1,100,13.09000015258789,13.020999908447266,0.069000244140625,100.52992248535156
4,TO,binary,1,100,13.031000137329102,13.020999908447266,0.010000228881835938,100.0768051147461
5,TO,binary,1,100,13.083000183105469,13.020999908447266,0.062000274658203125,100.47615814208984
6,TO,binary,1,100,13.064000129699707,13.020999908447266,0.043000221252441406,100.33023071289062
0,FROM,binary,1,1000,15.451000213623047,15.451000213623047,0.0,100.0
1,FROM,binary,1,1000,15.324000358581543,15.451000213623047,-0.1269998550415039,99.17804718017578
2,FROM,binary,1,1000,15.744000434875488,15.451000213623047,0.2930002212524414,101.89632415771484
3,FROM,binary,1,1000,15.437000274658203,15.451000213623047,-0.01399993896484375,99.90938568115234
4,FROM,binary,1,1000,15.50100040435791,15.451000213623047,0.05000019073486328,100.3236083984375
5,FROM,binary,1,1000,15.418000221252441,15.451000213623047,-0.03299999237060547,99.78641510009766
6,FROM,binary,1,1000,15.437000274658203,15.451000213623047,-0.01399993896484375,99.90938568115234
0,TO,binary,1,1000,13.15999984741211,13.15999984741211,0.0,100.0
1,TO,binary,1,1000,13.152999877929688,13.15999984741211,-0.006999969482421875,99.94680786132812
2,TO,binary,1,1000,13.121999740600586,13.15999984741211,-0.03800010681152344,99.71124267578125
3,TO,binary,1,1000,13.112000465393066,13.15999984741211,-0.04799938201904297,99.63526153564453
4,TO,binary,1,1000,13.135000228881836,13.15999984741211,-0.024999618530273438,99.8100357055664
5,TO,binary,1,1000,13.184000015258789,13.15999984741211,0.024000167846679688,100.18236541748047
6,TO,binary,1,1000,13.053999900817871,13.15999984741211,-0.10599994659423828,99.19452667236328
0,FROM,binary,1,10000,15.899999618530273,15.899999618530273,0.0,100.0
1,FROM,binary,1,10000,15.91349983215332,15.899999618530273,0.013500213623046875,100.08491516113281
2,FROM,binary,1,10000,15.820999145507812,15.899999618530273,-0.07900047302246094,99.50314331054688
3,FROM,binary,1,10000,15.892499923706055,15.899999618530273,-0.00749969482421875,99.95283508300781
4,FROM,binary,1,10000,15.822500228881836,15.899999618530273,-0.0774993896484375,99.51258087158203
5,FROM,binary,1,10000,15.932000160217285,15.899999618530273,0.03200054168701172,100.20126342773438
6,FROM,binary,1,10000,15.859999656677246,15.899999618530273,-0.039999961853027344,99.74842834472656
0,TO,binary,1,10000,13.954500198364258,13.954500198364258,0.0,100.0
1,TO,binary,1,10000,13.930500030517578,13.954500198364258,-0.024000167846679688,99.82801055908203
2,TO,binary,1,10000,13.955999374389648,13.954500198364258,0.001499176025390625,100.0107421875
3,TO,binary,1,10000,13.901000022888184,13.954500198364258,-0.05350017547607422,99.61660766601562
4,TO,binary,1,10000,13.966500282287598,13.954500198364258,0.012000083923339844,100.08599853515625
5,TO,binary,1,10000,13.955499649047852,13.954500198364258,0.00099945068359375,100.00716400146484
6,TO,binary,1,10000,13.942500114440918,13.954500198364258,-0.012000083923339844,99.91400909423828
0,FROM,binary,1,100000,20.302000045776367,20.302000045776367,0.0,100.0
1,FROM,binary,1,100000,20.517000198364258,20.302000045776367,0.21500015258789062,101.05900573730469
2,FROM,binary,1,100000,20.320999145507812,20.302000045776367,0.018999099731445312,100.09358215332031
3,FROM,binary,1,100000,20.43600082397461,20.302000045776367,0.1340007781982422,100.6600341796875
4,FROM,binary,1,100000,20.351999282836914,20.302000045776367,0.049999237060546875,100.24627685546875
5,FROM,binary,1,100000,20.398000717163086,20.302000045776367,0.09600067138671875,100.47286987304688
6,FROM,binary,1,100000,20.20400047302246,20.302000045776367,-0.09799957275390625,99.51728820800781
0,TO,binary,1,100000,22.125999450683594,22.125999450683594,0.0,100.0
1,TO,binary,1,100000,22.04800033569336,22.125999450683594,-0.07799911499023438,99.6474838256836
2,TO,binary,1,100000,22.18899917602539,22.125999450683594,0.06299972534179688,100.28472900390625
3,TO,binary,1,100000,22.174999237060547,22.125999450683594,0.048999786376953125,100.2214584350586
4,TO,binary,1,100000,22.065000534057617,22.125999450683594,-0.06099891662597656,99.72431182861328
5,TO,binary,1,100000,22.136999130249023,22.125999450683594,0.010999679565429688,100.04971313476562
6,TO,binary,1,100000,22.100000381469727,22.125999450683594,-0.025999069213867188,99.88249206542969
0,FROM,binary,1,1000000,64.92400360107422,64.92400360107422,0.0,100.0
1,FROM,binary,1,1000000,66.70800018310547,64.92400360107422,1.78399658203125,102.74781799316406
2,FROM,binary,1,1000000,64.31800079345703,64.92400360107422,-0.6060028076171875,99.06659698486328
3,FROM,binary,1,1000000,65.41600036621094,64.92400360107422,0.49199676513671875,100.75780487060547
4,FROM,binary,1,1000000,64.16600036621094,64.92400360107422,-0.7580032348632812,98.83247375488281
5,FROM,binary,1,1000000,63.862998962402344,64.92400360107422,-1.061004638671875,98.36576843261719
6,FROM,binary,1,1000000,63.66400146484375,64.92400360107422,-1.2600021362304688,98.05926513671875
0,TO,binary,1,1000000,100.66100311279297,100.66100311279297,0.0,100.0
1,TO,binary,1,1000000,100.81900024414062,100.66100311279297,0.15799713134765625,100.1569595336914
2,TO,binary,1,1000000,100.79000091552734,100.66100311279297,0.128997802734375,100.1281509399414
3,TO,binary,1,1000000,100.83499908447266,100.66100311279297,0.1739959716796875,100.1728515625
4,TO,binary,1,1000000,101.1520004272461,100.66100311279297,0.490997314453125,100.4877700805664
5,TO,binary,1,1000000,101.68299865722656,100.66100311279297,1.0219955444335938,101.0152816772461
6,TO,binary,1,1000000,101.88400268554688,100.66100311279297,1.2229995727539062,101.2149658203125
0,FROM,binary,10,10,13.33899974822998,13.33899974822998,0.0,100.0
1,FROM,binary,10,10,13.321999549865723,13.33899974822998,-0.017000198364257812,99.87255096435547
2,FROM,binary,10,10,13.291999816894531,13.33899974822998,-0.04699993133544922,99.64765167236328
3,FROM,binary,10,10,13.293000221252441,13.33899974822998,-0.04599952697753906,99.6551513671875
4,FROM,binary,10,10,13.263999938964844,13.33899974822998,-0.07499980926513672,99.43773651123047
5,FROM,binary,10,10,13.397000312805176,13.33899974822998,0.05800056457519531,100.434814453125
6,FROM,binary,10,10,13.27400016784668,13.33899974822998,-0.06499958038330078,99.51271057128906
0,TO,binary,10,10,12.994999885559082,12.994999885559082,0.0,100.0
1,TO,binary,10,10,12.970999717712402,12.994999885559082,-0.024000167846679688,99.81531524658203
2,TO,binary,10,10,13.015999794006348,12.994999885559082,0.020999908447265625,100.1615982055664
3,TO,binary,10,10,13.062000274658203,12.994999885559082,0.0670003890991211,100.51557922363281
4,TO,binary,10,10,13.064000129699707,12.994999885559082,0.069000244140625,100.53096771240234
5,TO,binary,10,10,13.069999694824219,12.994999885559082,0.07499980926513672,100.57714080810547
6,TO,binary,10,10,12.967000007629395,12.994999885559082,-0.0279998779296875,99.78453826904297
0,FROM,binary,10,100,13.371999740600586,13.371999740600586,0.0,100.0
1,FROM,binary,10,100,13.458999633789062,13.371999740600586,0.08699989318847656,100.6506118774414
2,FROM,binary,10,100,13.460000038146973,13.371999740600586,0.08800029754638672,100.65809631347656
3,FROM,binary,10,100,13.404999732971191,13.371999740600586,0.03299999237060547,100.24678802490234
4,FROM,binary,10,100,13.413999557495117,13.371999740600586,0.04199981689453125,100.31409454345703
5,FROM,binary,10,100,13.456000328063965,13.371999740600586,0.0840005874633789,100.62818908691406
6,FROM,binary,10,100,13.432999610900879,13.371999740600586,0.06099987030029297,100.4561767578125
0,TO,binary,10,100,12.993000030517578,12.993000030517578,0.0,100.0
1,TO,binary,10,100,13.097000122070312,12.993000030517578,0.10400009155273438,100.80043029785156
2,TO,binary,10,100,13.147000312805176,12.993000030517578,0.15400028228759766,101.18524932861328
3,TO,binary,10,100,13.050999641418457,12.993000030517578,0.057999610900878906,100.4463882446289
4,TO,binary,10,100,13.105999946594238,12.993000030517578,0.11299991607666016,100.86970520019531
5,TO,binary,10,100,13.125,12.993000030517578,0.13199996948242188,101.01593780517578
6,TO,binary,10,100,13.050000190734863,12.993000030517578,0.057000160217285156,100.43870544433594
0,FROM,binary,10,1000,15.597000122070312,15.597000122070312,0.0,100.0
1,FROM,binary,10,1000,15.519000053405762,15.597000122070312,-0.07800006866455078,99.49990844726562
2,FROM,binary,10,1000,15.708999633789062,15.597000122070312,0.11199951171875,100.71807861328125
3,FROM,binary,10,1000,15.506999969482422,15.597000122070312,-0.09000015258789062,99.42296600341797
4,FROM,binary,10,1000,15.53600025177002,15.597000122070312,-0.06099987030029297,99.60890197753906
5,FROM,binary,10,1000,15.743000030517578,15.597000122070312,0.14599990844726562,100.93608093261719
6,FROM,binary,10,1000,15.684000015258789,15.597000122070312,0.08699989318847656,100.55780029296875
0,TO,binary,10,1000,13.359999656677246,13.359999656677246,0.0,100.0
1,TO,binary,10,1000,13.395000457763672,13.359999656677246,0.03500080108642578,100.2619857788086
2,TO,binary,10,1000,13.369000434875488,13.359999656677246,0.009000778198242188,100.06736755371094
3,TO,binary,10,1000,13.378000259399414,13.359999656677246,0.01800060272216797,100.13472747802734
4,TO,binary,10,1000,13.307000160217285,13.359999656677246,-0.05299949645996094,99.6032943725586
5,TO,binary,10,1000,13.342000007629395,13.359999656677246,-0.017999649047851562,99.86527252197266
6,TO,binary,10,1000,13.322999954223633,13.359999656677246,-0.03699970245361328,99.72306060791016
0,FROM,binary,10,10000,17.267000198364258,17.267000198364258,0.0,100.0
1,FROM,binary,10,10000,17.252500534057617,17.267000198364258,-0.014499664306640625,99.91603088378906
2,FROM,binary,10,10000,17.104000091552734,17.267000198364258,-0.16300010681152344,99.05599975585938
3,FROM,binary,10,10000,17.18000030517578,17.267000198364258,-0.08699989318847656,99.49614715576172
4,FROM,binary,10,10000,17.131999969482422,17.267000198364258,-0.13500022888183594,99.2181625366211
5,FROM,binary,10,10000,17.250999450683594,17.267000198364258,-0.016000747680664062,99.90733337402344
6,FROM,binary,10,10000,17.121999740600586,17.267000198364258,-0.14500045776367188,99.16024780273438
0,TO,binary,10,10000,16.187000274658203,16.187000274658203,0.0,100.0
1,TO,binary,10,10000,16.17099952697754,16.187000274658203,-0.016000747680664062,99.90115356445312
2,TO,binary,10,10000,16.20600128173828,16.187000274658203,0.019001007080078125,100.11738586425781
3,TO,binary,10,10000,16.185001373291016,16.187000274658203,-0.0019989013671875,99.9876480102539
4,TO,binary,10,10000,16.26650047302246,16.187000274658203,0.07950019836425781,100.49112701416016
5,TO,binary,10,10000,16.240001678466797,16.187000274658203,0.05300140380859375,100.32743072509766
6,TO,binary,10,10000,16.128999710083008,16.187000274658203,-0.05800056457519531,99.64168548583984
0,FROM,binary,10,100000,33.06800079345703,33.06800079345703,0.0,100.0
1,FROM,binary,10,100000,34.0880012512207,33.06800079345703,1.0200004577636719,103.08454895019531
2,FROM,binary,10,100000,32.994998931884766,33.06800079345703,-0.07300186157226562,99.77923583984375
3,FROM,binary,10,100000,33.06800079345703,33.06800079345703,0.0,100.0
4,FROM,binary,10,100000,32.8849983215332,33.06800079345703,-0.18300247192382812,99.44658660888672
5,FROM,binary,10,100000,32.92100143432617,33.06800079345703,-0.14699935913085938,99.55546569824219
6,FROM,binary,10,100000,32.95600128173828,33.06800079345703,-0.11199951171875,99.66130065917969
0,TO,binary,10,100000,44.237998962402344,44.237998962402344,0.0,100.0
1,TO,binary,10,100000,44.29600143432617,44.237998962402344,0.058002471923828125,100.13111877441406
2,TO,binary,10,100000,44.25,44.237998962402344,0.01200103759765625,100.02713012695312
3,TO,binary,10,100000,44.242000579833984,44.237998962402344,0.004001617431640625,100.00904846191406
4,TO,binary,10,100000,44.347999572753906,44.237998962402344,0.1100006103515625,100.2486572265625
5,TO,binary,10,100000,44.59199905395508,44.237998962402344,0.3540000915527344,100.80021667480469
6,TO,binary,10,100000,44.7400016784668,44.237998962402344,0.5020027160644531,101.13478088378906
0,FROM,binary,10,1000000,188.11000061035156,188.11000061035156,0.0,100.0
1,FROM,binary,10,1000000,197.8470001220703,188.11000061035156,9.73699951171875,105.17622375488281
2,FROM,binary,10,1000000,188.03900146484375,188.11000061035156,-0.0709991455078125,99.9622573852539
3,FROM,binary,10,1000000,187.73500061035156,188.11000061035156,-0.375,99.80064392089844
4,FROM,binary,10,1000000,187.98599243164062,188.11000061035156,-0.1240081787109375,99.93407440185547
5,FROM,binary,10,1000000,188.07400512695312,188.11000061035156,-0.0359954833984375,99.98086547851562
6,FROM,binary,10,1000000,187.66000366210938,188.11000061035156,-0.4499969482421875,99.76078033447266
0,TO,binary,10,1000000,322.114013671875,322.114013671875,0.0,100.0
1,TO,binary,10,1000000,324.62298583984375,322.114013671875,2.50897216796875,100.77891540527344
2,TO,binary,10,1000000,323.5169982910156,322.114013671875,1.402984619140625,100.43555450439453
3,TO,binary,10,1000000,324.7690124511719,322.114013671875,2.654998779296875,100.82423400878906
4,TO,binary,10,1000000,326.1669921875,322.114013671875,4.052978515625,101.25823974609375
5,TO,binary,10,1000000,328.4110107421875,322.114013671875,6.2969970703125,101.95490264892578
6,TO,binary,10,1000000,328.25201416015625,322.114013671875,6.13800048828125,101.90553283691406
0,FROM,binary,100,10,13.434000015258789,13.434000015258789,0.0,100.0
1,FROM,binary,100,10,13.39799976348877,13.434000015258789,-0.03600025177001953,99.73202514648438
2,FROM,binary,100,10,13.413999557495117,13.434000015258789,-0.020000457763671875,99.85111999511719
3,FROM,binary,100,10,13.440999984741211,13.434000015258789,0.006999969482421875,100.05210876464844
4,FROM,binary,100,10,13.357000350952148,13.434000015258789,-0.07699966430664062,99.42682647705078
5,FROM,binary,100,10,13.520000457763672,13.434000015258789,0.08600044250488281,100.64016723632812
6,FROM,binary,100,10,13.4399995803833,13.434000015258789,0.005999565124511719,100.0446548461914
0,TO,binary,100,10,13.14799976348877,13.14799976348877,0.0,100.0
1,TO,binary,100,10,13.154000282287598,13.14799976348877,0.006000518798828125,100.0456314086914
2,TO,binary,100,10,13.119999885559082,13.14799976348877,-0.0279998779296875,99.78704071044922
3,TO,binary,100,10,13.13599967956543,13.14799976348877,-0.012000083923339844,99.90873718261719
4,TO,binary,100,10,13.152000427246094,13.14799976348877,0.004000663757324219,100.03042602539062
5,TO,binary,100,10,13.192000389099121,13.14799976348877,0.04400062561035156,100.33465576171875
6,TO,binary,100,10,13.161999702453613,13.14799976348877,0.01399993896484375,100.10647583007812
0,FROM,binary,100,100,13.682000160217285,13.682000160217285,0.0,100.0
1,FROM,binary,100,100,13.86299991607666,13.682000160217285,0.180999755859375,101.3228988647461
2,FROM,binary,100,100,13.663999557495117,13.682000160217285,-0.01800060272216797,99.8684310913086
3,FROM,binary,100,100,13.708000183105469,13.682000160217285,0.026000022888183594,100.19003295898438
4,FROM,binary,100,100,13.607000350952148,13.682000160217285,-0.07499980926513672,99.45183563232422
5,FROM,binary,100,100,13.694999694824219,13.682000160217285,0.012999534606933594,100.09500885009766
6,FROM,binary,100,100,13.6899995803833,13.682000160217285,0.007999420166015625,100.0584716796875
0,TO,binary,100,100,13.220000267028809,13.220000267028809,0.0,100.0
1,TO,binary,100,100,13.244000434875488,13.220000267028809,0.024000167846679688,100.1815414428711
2,TO,binary,100,100,13.42199993133545,13.220000267028809,0.20199966430664062,101.52799224853516
3,TO,binary,100,100,13.32800006866455,13.220000267028809,0.10799980163574219,100.81694030761719
4,TO,binary,100,100,13.303999900817871,13.220000267028809,0.0839996337890625,100.6353988647461
5,TO,binary,100,100,13.317999839782715,13.220000267028809,0.09799957275390625,100.74130249023438
6,TO,binary,100,100,13.293000221252441,13.220000267028809,0.07299995422363281,100.55219268798828
0,FROM,binary,100,1000,17.319000244140625,17.319000244140625,0.0,100.0
1,FROM,binary,100,1000,17.39699935913086,17.319000244140625,0.07799911499023438,100.45037078857422
2,FROM,binary,100,1000,17.261999130249023,17.319000244140625,-0.05700111389160156,99.6708755493164
3,FROM,binary,100,1000,17.27400016784668,17.319000244140625,-0.04500007629394531,99.74017333984375
4,FROM,binary,100,1000,17.197999954223633,17.319000244140625,-0.12100028991699219,99.30134582519531
5,FROM,binary,100,1000,17.371999740600586,17.319000244140625,0.05299949645996094,100.30602264404297
6,FROM,binary,100,1000,17.10700035095215,17.319000244140625,-0.21199989318847656,98.77590942382812
0,TO,binary,100,1000,15.460000038146973,15.460000038146973,0.0,100.0
1,TO,binary,100,1000,15.289999961853027,15.460000038146973,-0.1700000762939453,98.900390625
2,TO,binary,100,1000,15.25100040435791,15.460000038146973,-0.2089996337890625,98.64812469482422
3,TO,binary,100,1000,15.27400016784668,15.460000038146973,-0.18599987030029297,98.7968978881836
4,TO,binary,100,1000,15.27299976348877,15.460000038146973,-0.18700027465820312,98.7904281616211
5,TO,binary,100,1000,15.329999923706055,15.460000038146973,-0.13000011444091797,99.15911865234375
6,TO,binary,100,1000,15.413000106811523,15.460000038146973,-0.04699993133544922,99.69599151611328
0,FROM,binary,100,10000,30.11949920654297,30.11949920654297,0.0,100.0
1,FROM,binary,100,10000,31.08449935913086,30.11949920654297,0.9650001525878906,103.20390319824219
2,FROM,binary,100,10000,30.047000885009766,30.11949920654297,-0.07249832153320312,99.7593002319336
3,FROM,binary,100,10000,30.044498443603516,30.11949920654297,-0.07500076293945312,99.75099182128906
4,FROM,binary,100,10000,30.003999710083008,30.11949920654297,-0.11549949645996094,99.61653137207031
5,FROM,binary,100,10000,30.07849884033203,30.11949920654297,-0.0410003662109375,99.86387634277344
6,FROM,binary,100,10000,30.002498626708984,30.11949920654297,-0.11700057983398438,99.61154174804688
0,TO,binary,100,10000,35.29399871826172,35.29399871826172,0.0,100.0
1,TO,binary,100,10000,35.32749938964844,35.29399871826172,0.03350067138671875,100.09491729736328
2,TO,binary,100,10000,35.33650207519531,35.29399871826172,0.04250335693359375,100.12042236328125
3,TO,binary,100,10000,35.39849853515625,35.29399871826172,0.10449981689453125,100.29608154296875
4,TO,binary,100,10000,35.30649948120117,35.29399871826172,0.012500762939453125,100.03541564941406
5,TO,binary,100,10000,35.57500076293945,35.29399871826172,0.2810020446777344,100.79617309570312
6,TO,binary,100,10000,35.635498046875,35.29399871826172,0.34149932861328125,100.96758270263672
0,FROM,binary,100,100000,154.27699279785156,154.27699279785156,0.0,100.0
1,FROM,binary,100,100000,165.56500244140625,154.27699279785156,11.288009643554688,107.31671905517578
2,FROM,binary,100,100000,155.36900329589844,154.27699279785156,1.092010498046875,100.70783233642578
3,FROM,binary,100,100000,155.50100708007812,154.27699279785156,1.2240142822265625,100.79338836669922
4,FROM,binary,100,100000,155.822998046875,154.27699279785156,1.5460052490234375,101.0020980834961
5,FROM,binary,100,100000,156.4409942626953,154.27699279785156,2.16400146484375,101.40267944335938
6,FROM,binary,100,100000,156.65199279785156,154.27699279785156,2.375,101.53943634033203
0,TO,binary,100,100000,233.95899963378906,233.95899963378906,0.0,100.0
1,TO,binary,100,100000,236.4040069580078,233.95899963378906,2.44500732421875,101.04505920410156
2,TO,binary,100,100000,236.0330047607422,233.95899963378906,2.074005126953125,100.88648986816406
3,TO,binary,100,100000,236.6269989013672,233.95899963378906,2.667999267578125,101.14036560058594
4,TO,binary,100,100000,237.23199462890625,233.95899963378906,3.2729949951171875,101.39895629882812
5,TO,binary,100,100000,238.35299682617188,233.95899963378906,4.3939971923828125,101.87810516357422
6,TO,binary,100,100000,238.83399963378906,233.95899963378906,4.875,102.08369445800781
0,FROM,binary,100,1000000,1398.7640380859375,1398.7640380859375,0.0,100.0
1,FROM,binary,100,1000000,1509.5899658203125,1398.7640380859375,110.825927734375,107.92314147949219
2,FROM,binary,100,1000000,1406.3389892578125,1398.7640380859375,7.574951171875,100.54154205322266
3,FROM,binary,100,1000000,1407.8719482421875,1398.7640380859375,9.10791015625,100.6511459350586
4,FROM,binary,100,1000000,1411.637939453125,1398.7640380859375,12.8739013671875,100.92037963867188
5,FROM,binary,100,1000000,1411.5570068359375,1398.7640380859375,12.79296875,100.91458892822266
6,FROM,binary,100,1000000,1406.073974609375,1398.7640380859375,7.3099365234375,100.52259826660156
0,TO,binary,100,1000000,2197.51708984375,2197.51708984375,0.0,100.0
1,TO,binary,100,1000000,2232.740966796875,2197.51708984375,35.223876953125,101.60289764404297
2,TO,binary,100,1000000,2220.89697265625,2197.51708984375,23.3798828125,101.06391906738281
3,TO,binary,100,1000000,2205.347900390625,2197.51708984375,7.830810546875,100.35635375976562
4,TO,binary,100,1000000,2207.029052734375,2197.51708984375,9.511962890625,100.43284606933594
5,TO,binary,100,1000000,2239.06201171875,2197.51708984375,41.544921875,101.89054107666016
6,TO,binary,100,1000000,2217.830078125,2197.51708984375,20.31298828125,100.92436218261719
0,FROM,csv,1,10,13.366999626159668,13.366999626159668,0.0,100.0
1,FROM,csv,1,10,13.295999526977539,13.366999626159668,-0.0710000991821289,99.46884155273438
2,FROM,csv,1,10,13.342000007629395,13.366999626159668,-0.024999618530273438,99.81297302246094
3,FROM,csv,1,10,13.33899974822998,13.366999626159668,-0.0279998779296875,99.79053497314453
4,FROM,csv,1,10,13.187999725341797,13.366999626159668,-0.1789999008178711,98.66088104248047
5,FROM,csv,1,10,13.361000061035156,13.366999626159668,-0.005999565124511719,99.95511627197266
6,FROM,csv,1,10,13.418000221252441,13.366999626159668,0.05100059509277344,100.38153839111328
0,TO,csv,1,10,13.017999649047852,13.017999649047852,0.0,100.0
1,TO,csv,1,10,13.038000106811523,13.017999649047852,0.020000457763671875,100.15364074707031
2,TO,csv,1,10,12.989999771118164,13.017999649047852,-0.0279998779296875,99.78491973876953
3,TO,csv,1,10,13.0,13.017999649047852,-0.017999649047851562,99.86173248291016
4,TO,csv,1,10,13.020999908447266,13.017999649047852,0.0030002593994140625,100.02304077148438
5,TO,csv,1,10,13.166000366210938,13.017999649047852,0.14800071716308594,101.13688659667969
6,TO,csv,1,10,12.95199966430664,13.017999649047852,-0.06599998474121094,99.49301147460938
0,FROM,csv,1,100,13.416000366210938,13.416000366210938,0.0,100.0
1,FROM,csv,1,100,13.493000030517578,13.416000366210938,0.07699966430664062,100.57393646240234
2,FROM,csv,1,100,13.50100040435791,13.416000366210938,0.08500003814697266,100.63357543945312
3,FROM,csv,1,100,13.489999771118164,13.416000366210938,0.07399940490722656,100.55158233642578
4,FROM,csv,1,100,13.366000175476074,13.416000366210938,-0.05000019073486328,99.62731170654297
5,FROM,csv,1,100,13.477999687194824,13.416000366210938,0.06199932098388672,100.46212768554688
6,FROM,csv,1,100,13.470000267028809,13.416000366210938,0.053999900817871094,100.40249633789062
0,TO,csv,1,100,13.005999565124512,13.005999565124512,0.0,100.0
1,TO,csv,1,100,13.032999992370605,13.005999565124512,0.02700042724609375,100.20760345458984
2,TO,csv,1,100,13.029000282287598,13.005999565124512,0.023000717163085938,100.17684936523438
3,TO,csv,1,100,13.069000244140625,13.005999565124512,0.06300067901611328,100.4843978881836
4,TO,csv,1,100,13.015999794006348,13.005999565124512,0.010000228881835938,100.07688903808594
5,TO,csv,1,100,13.093000411987305,13.005999565124512,0.08700084686279297,100.66893005371094
6,TO,csv,1,100,12.986000061035156,13.005999565124512,-0.01999950408935547,99.84622955322266
0,FROM,csv,1,1000,15.545999526977539,15.545999526977539,0.0,100.0
1,FROM,csv,1,1000,15.406000137329102,15.545999526977539,-0.1399993896484375,99.09944915771484
2,FROM,csv,1,1000,15.513999938964844,15.545999526977539,-0.03199958801269531,99.79415893554688
3,FROM,csv,1,1000,15.541000366210938,15.545999526977539,-0.0049991607666015625,99.96784210205078
4,FROM,csv,1,1000,15.482000350952148,15.545999526977539,-0.06399917602539062,99.58832550048828
5,FROM,csv,1,1000,15.463000297546387,15.545999526977539,-0.08299922943115234,99.46610260009766
6,FROM,csv,1,1000,15.461999893188477,15.545999526977539,-0.0839996337890625,99.45967102050781
0,TO,csv,1,1000,13.138999938964844,13.138999938964844,0.0,100.0
1,TO,csv,1,1000,13.192999839782715,13.138999938964844,0.053999900817871094,100.4109878540039
2,TO,csv,1,1000,13.071000099182129,13.138999938964844,-0.06799983978271484,99.48246002197266
3,TO,csv,1,1000,13.192000389099121,13.138999938964844,0.053000450134277344,100.40338134765625
4,TO,csv,1,1000,13.057000160217285,13.138999938964844,-0.0819997787475586,99.37590026855469
5,TO,csv,1,1000,13.243000030517578,13.138999938964844,0.10400009155273438,100.79153442382812
6,TO,csv,1,1000,13.145000457763672,13.138999938964844,0.006000518798828125,100.04566955566406
0,FROM,csv,1,10000,16.08799934387207,16.08799934387207,0.0,100.0
1,FROM,csv,1,10000,16.04450035095215,16.08799934387207,-0.043498992919921875,99.7296142578125
2,FROM,csv,1,10000,16.07849884033203,16.08799934387207,-0.009500503540039062,99.9409408569336
3,FROM,csv,1,10000,16.08650016784668,16.08799934387207,-0.001499176025390625,99.99068450927734
4,FROM,csv,1,10000,16.00749969482422,16.08799934387207,-0.08049964904785156,99.4996337890625
5,FROM,csv,1,10000,16.176000595092773,16.08799934387207,0.08800125122070312,100.54700469970703
6,FROM,csv,1,10000,16.13249969482422,16.08799934387207,0.04450035095214844,100.27660369873047
0,TO,csv,1,10000,13.92300033569336,13.92300033569336,0.0,100.0
1,TO,csv,1,10000,13.899999618530273,13.92300033569336,-0.023000717163085938,99.83480072021484
2,TO,csv,1,10000,13.90250015258789,13.92300033569336,-0.02050018310546875,99.8527603149414
3,TO,csv,1,10000,14.031999588012695,13.92300033569336,0.10899925231933594,100.78286743164062
4,TO,csv,1,10000,13.868999481201172,13.92300033569336,-0.0540008544921875,99.61214447021484
5,TO,csv,1,10000,13.94849967956543,13.92300033569336,0.025499343872070312,100.18314361572266
6,TO,csv,1,10000,13.889999389648438,13.92300033569336,-0.033000946044921875,99.76297760009766
0,FROM,csv,1,100000,21.698999404907227,21.698999404907227,0.0,100.0
1,FROM,csv,1,100000,21.68199920654297,21.698999404907227,-0.017000198364257812,99.9216537475586
2,FROM,csv,1,100000,21.83099937438965,21.698999404907227,0.13199996948242188,100.60832214355469
3,FROM,csv,1,100000,22.01300048828125,21.698999404907227,0.31400108337402344,101.44708251953125
4,FROM,csv,1,100000,21.735000610351562,21.698999404907227,0.03600120544433594,100.1659164428711
5,FROM,csv,1,100000,21.768999099731445,21.698999404907227,0.06999969482421875,100.32259368896484
6,FROM,csv,1,100000,21.770999908447266,21.698999404907227,0.07200050354003906,100.33181762695312
0,TO,csv,1,100000,21.834999084472656,21.834999084472656,0.0,100.0
1,TO,csv,1,100000,21.836000442504883,21.834999084472656,0.0010013580322265625,100.00459289550781
2,TO,csv,1,100000,21.902999877929688,21.834999084472656,0.06800079345703125,100.31143188476562
3,TO,csv,1,100000,21.881999969482422,21.834999084472656,0.047000885009765625,100.21525573730469
4,TO,csv,1,100000,21.958999633789062,21.834999084472656,0.12400054931640625,100.56790161132812
5,TO,csv,1,100000,21.756999969482422,21.834999084472656,-0.07799911499023438,99.64277648925781
6,TO,csv,1,100000,21.81599998474121,21.834999084472656,-0.018999099731445312,99.9129867553711
0,FROM,csv,1,1000000,77.19000244140625,77.19000244140625,0.0,100.0
1,FROM,csv,1,1000000,77.40399932861328,77.19000244140625,0.21399688720703125,100.27723693847656
2,FROM,csv,1,1000000,78.7229995727539,77.19000244140625,1.5329971313476562,101.98600006103516
3,FROM,csv,1,1000000,81.11699676513672,77.19000244140625,3.9269943237304688,105.08743286132812
4,FROM,csv,1,1000000,78.06300354003906,77.19000244140625,0.8730010986328125,101.13097381591797
5,FROM,csv,1,1000000,77.73799896240234,77.19000244140625,0.5479965209960938,100.70993041992188
6,FROM,csv,1,1000000,78.01899719238281,77.19000244140625,0.8289947509765625,101.07396697998047
0,TO,csv,1,1000000,98.53700256347656,98.53700256347656,0.0,100.0
1,TO,csv,1,1000000,98.16999816894531,98.53700256347656,-0.36700439453125,99.62754821777344
2,TO,csv,1,1000000,98.30400085449219,98.53700256347656,-0.233001708984375,99.76353454589844
3,TO,csv,1,1000000,98.17500305175781,98.53700256347656,-0.36199951171875,99.63262939453125
4,TO,csv,1,1000000,99.19499969482422,98.53700256347656,0.6579971313476562,100.66776275634766
5,TO,csv,1,1000000,98.67900085449219,98.53700256347656,0.141998291015625,100.14411163330078
6,TO,csv,1,1000000,99.12699890136719,98.53700256347656,0.589996337890625,100.5987548828125
0,FROM,csv,10,10,13.295000076293945,13.295000076293945,0.0,100.0
1,FROM,csv,10,10,13.319999694824219,13.295000076293945,0.024999618530273438,100.18804168701172
2,FROM,csv,10,10,13.375,13.295000076293945,0.07999992370605469,100.60173034667969
3,FROM,csv,10,10,13.347999572753906,13.295000076293945,0.05299949645996094,100.39865112304688
4,FROM,csv,10,10,13.246999740600586,13.295000076293945,-0.048000335693359375,99.63895416259766
5,FROM,csv,10,10,13.527999877929688,13.295000076293945,0.2329998016357422,101.75253295898438
6,FROM,csv,10,10,13.319000244140625,13.295000076293945,0.024000167846679688,100.1805191040039
0,TO,csv,10,10,13.008999824523926,13.008999824523926,0.0,100.0
1,TO,csv,10,10,13.057000160217285,13.008999824523926,0.048000335693359375,100.36897277832031
2,TO,csv,10,10,13.062000274658203,13.008999824523926,0.053000450134277344,100.40740966796875
3,TO,csv,10,10,13.027999877929688,13.008999824523926,0.01900005340576172,100.14605712890625
4,TO,csv,10,10,13.019000053405762,13.008999824523926,0.010000228881835938,100.07686614990234
5,TO,csv,10,10,13.199999809265137,13.008999824523926,0.19099998474121094,101.46821594238281
6,TO,csv,10,10,13.067999839782715,13.008999824523926,0.05900001525878906,100.45352935791016
0,FROM,csv,10,100,13.506999969482422,13.506999969482422,0.0,100.0
1,FROM,csv,10,100,13.480999946594238,13.506999969482422,-0.026000022888183594,99.80751037597656
2,FROM,csv,10,100,13.440999984741211,13.506999969482422,-0.06599998474121094,99.51136779785156
3,FROM,csv,10,100,13.359000205993652,13.506999969482422,-0.14799976348876953,98.9042739868164
4,FROM,csv,10,100,13.329999923706055,13.506999969482422,-0.1770000457763672,98.68956756591797
5,FROM,csv,10,100,13.508000373840332,13.506999969482422,0.0010004043579101562,100.00740051269531
6,FROM,csv,10,100,13.482000350952148,13.506999969482422,-0.024999618530273438,99.8149185180664
0,TO,csv,10,100,13.0600004196167,13.0600004196167,0.0,100.0
1,TO,csv,10,100,13.045999526977539,13.0600004196167,-0.014000892639160156,99.89279174804688
2,TO,csv,10,100,13.026000022888184,13.0600004196167,-0.034000396728515625,99.73966217041016
3,TO,csv,10,100,13.003000259399414,13.0600004196167,-0.057000160217285156,99.56355285644531
4,TO,csv,10,100,13.043999671936035,13.0600004196167,-0.016000747680664062,99.87747955322266
5,TO,csv,10,100,13.12600040435791,13.0600004196167,0.06599998474121094,100.50536346435547
6,TO,csv,10,100,13.067000389099121,13.0600004196167,0.006999969482421875,100.05359649658203
0,FROM,csv,10,1000,15.758000373840332,15.758000373840332,0.0,100.0
1,FROM,csv,10,1000,15.71500015258789,15.758000373840332,-0.043000221252441406,99.72712707519531
2,FROM,csv,10,1000,15.746999740600586,15.758000373840332,-0.011000633239746094,99.93019104003906
3,FROM,csv,10,1000,15.79800033569336,15.758000373840332,0.039999961853027344,100.25384521484375
4,FROM,csv,10,1000,15.651000022888184,15.758000373840332,-0.10700035095214844,99.32097625732422
5,FROM,csv,10,1000,15.680000305175781,15.758000373840332,-0.07800006866455078,99.50501251220703
6,FROM,csv,10,1000,15.789999961853027,15.758000373840332,0.03199958801269531,100.20307159423828
0,TO,csv,10,1000,13.256999969482422,13.256999969482422,0.0,100.0
1,TO,csv,10,1000,13.272000312805176,13.256999969482422,0.015000343322753906,100.11315155029297
2,TO,csv,10,1000,13.272000312805176,13.256999969482422,0.015000343322753906,100.11315155029297
3,TO,csv,10,1000,13.197999954223633,13.256999969482422,-0.05900001525878906,99.55494689941406
4,TO,csv,10,1000,13.288999557495117,13.256999969482422,0.03199958801269531,100.24137878417969
5,TO,csv,10,1000,13.348999977111816,13.256999969482422,0.09200000762939453,100.69397735595703
6,TO,csv,10,1000,13.25100040435791,13.256999969482422,-0.005999565124511719,99.95474243164062
0,FROM,csv,10,10000,17.811500549316406,17.811500549316406,0.0,100.0
1,FROM,csv,10,10000,17.681499481201172,17.811500549316406,-0.13000106811523438,99.27012634277344
2,FROM,csv,10,10000,17.74850082397461,17.811500549316406,-0.06299972534179688,99.64630126953125
3,FROM,csv,10,10000,17.73400115966797,17.811500549316406,-0.0774993896484375,99.56489562988281
4,FROM,csv,10,10000,17.749000549316406,17.811500549316406,-0.0625,99.64910125732422
5,FROM,csv,10,10000,17.795501708984375,17.811500549316406,-0.01599884033203125,99.9101791381836
6,FROM,csv,10,10000,17.737998962402344,17.811500549316406,-0.0735015869140625,99.58734130859375
0,TO,csv,10,10000,15.560999870300293,15.560999870300293,0.0,100.0
1,TO,csv,10,10000,15.519499778747559,15.560999870300293,-0.041500091552734375,99.73330688476562
2,TO,csv,10,10000,15.580999374389648,15.560999870300293,0.01999950408935547,100.1285171508789
3,TO,csv,10,10000,15.569000244140625,15.560999870300293,0.008000373840332031,100.0514144897461
4,TO,csv,10,10000,15.447000503540039,15.560999870300293,-0.1139993667602539,99.26740264892578
5,TO,csv,10,10000,15.55049991607666,15.560999870300293,-0.010499954223632812,99.9325180053711
6,TO,csv,10,10000,15.562999725341797,15.560999870300293,0.0019998550415039062,100.01284790039062
0,FROM,csv,10,100000,37.72100067138672,37.72100067138672,0.0,100.0
1,FROM,csv,10,100000,37.68899917602539,37.72100067138672,-0.032001495361328125,99.9151611328125
2,FROM,csv,10,100000,38.05699920654297,37.72100067138672,0.33599853515625,100.8907470703125
3,FROM,csv,10,100000,38.0890007019043,37.72100067138672,0.3680000305175781,100.9755859375
4,FROM,csv,10,100000,38.071998596191406,37.72100067138672,0.3509979248046875,100.93051147460938
5,FROM,csv,10,100000,37.86899948120117,37.72100067138672,0.14799880981445312,100.3923568725586
6,FROM,csv,10,100000,38.09700012207031,37.72100067138672,0.37599945068359375,100.99679565429688
0,TO,csv,10,100000,37.7400016784668,37.7400016784668,0.0,100.0
1,TO,csv,10,100000,37.39500045776367,37.7400016784668,-0.345001220703125,99.08584594726562
2,TO,csv,10,100000,37.479000091552734,37.7400016784668,-0.2610015869140625,99.30841827392578
3,TO,csv,10,100000,37.54899978637695,37.7400016784668,-0.19100189208984375,99.49390411376953
4,TO,csv,10,100000,37.58399963378906,37.7400016784668,-0.15600204467773438,99.58663940429688
5,TO,csv,10,100000,37.76100158691406,37.7400016784668,0.020999908447265625,100.05564880371094
6,TO,csv,10,100000,37.94900131225586,37.7400016784668,0.2089996337890625,100.55378723144531
0,FROM,csv,10,1000000,237.31500244140625,237.31500244140625,0.0,100.0
1,FROM,csv,10,1000000,237.14500427246094,237.31500244140625,-0.1699981689453125,99.9283676147461
2,FROM,csv,10,1000000,239.6529998779297,237.31500244140625,2.3379974365234375,100.98519134521484
3,FROM,csv,10,1000000,241.13099670410156,237.31500244140625,3.8159942626953125,101.60798645019531
4,FROM,csv,10,1000000,239.12399291992188,237.31500244140625,1.808990478515625,100.76226806640625
5,FROM,csv,10,1000000,238.656005859375,237.31500244140625,1.34100341796875,100.56507873535156
6,FROM,csv,10,1000000,241.86399841308594,237.31500244140625,4.5489959716796875,101.91686248779297
0,TO,csv,10,1000000,256.0010070800781,256.0010070800781,0.0,100.0
1,TO,csv,10,1000000,255.38699340820312,256.0010070800781,-0.614013671875,99.76014709472656
2,TO,csv,10,1000000,255.9550018310547,256.0010070800781,-0.0460052490234375,99.9820327758789
3,TO,csv,10,1000000,256.6669921875,256.0010070800781,0.665985107421875,100.26014709472656
4,TO,csv,10,1000000,257.2929992675781,256.0010070800781,1.2919921875,100.50468444824219
5,TO,csv,10,1000000,259.5559997558594,256.0010070800781,3.55499267578125,101.388671875
6,TO,csv,10,1000000,259.8330078125,256.0010070800781,3.832000732421875,101.49687194824219
0,FROM,csv,100,10,13.39799976348877,13.39799976348877,0.0,100.0
1,FROM,csv,100,10,13.395999908447266,13.39799976348877,-0.0019998550415039062,99.98507690429688
2,FROM,csv,100,10,13.279000282287598,13.39799976348877,-0.11899948120117188,99.11181640625
3,FROM,csv,100,10,13.532999992370605,13.39799976348877,0.13500022888183594,101.00761413574219
4,FROM,csv,100,10,13.175999641418457,13.39799976348877,-0.2220001220703125,98.34303283691406
5,FROM,csv,100,10,13.472999572753906,13.39799976348877,0.07499980926513672,100.55978393554688
6,FROM,csv,100,10,13.45300006866455,13.39799976348877,0.05500030517578125,100.41050720214844
0,TO,csv,100,10,13.069999694824219,13.069999694824219,0.0,100.0
1,TO,csv,100,10,13.062999725341797,13.069999694824219,-0.006999969482421875,99.94644165039062
2,TO,csv,100,10,13.038000106811523,13.069999694824219,-0.03199958801269531,99.75516510009766
3,TO,csv,100,10,13.1850004196167,13.069999694824219,0.11500072479248047,100.8798828125
4,TO,csv,100,10,13.125,13.069999694824219,0.05500030517578125,100.42080688476562
5,TO,csv,100,10,13.154999732971191,13.069999694824219,0.08500003814697266,100.65034484863281
6,TO,csv,100,10,13.097000122070312,13.069999694824219,0.02700042724609375,100.20658111572266
0,FROM,csv,100,100,13.753000259399414,13.753000259399414,0.0,100.0
1,FROM,csv,100,100,13.715999603271484,13.753000259399414,-0.03700065612792969,99.73096466064453
2,FROM,csv,100,100,13.784000396728516,13.753000259399414,0.031000137329101562,100.22540283203125
3,FROM,csv,100,100,13.744999885559082,13.753000259399414,-0.008000373840332031,99.94182586669922
4,FROM,csv,100,100,14.359000205993652,13.753000259399414,0.6059999465942383,104.40631103515625
5,FROM,csv,100,100,13.772000312805176,13.753000259399414,0.01900005340576172,100.13815307617188
6,FROM,csv,100,100,13.770000457763672,13.753000259399414,0.017000198364257812,100.12361145019531
0,TO,csv,100,100,13.34000015258789,13.34000015258789,0.0,100.0
1,TO,csv,100,100,13.227999687194824,13.34000015258789,-0.1120004653930664,99.16041564941406
2,TO,csv,100,100,13.303999900817871,13.34000015258789,-0.03600025177001953,99.73013305664062
3,TO,csv,100,100,13.248000144958496,13.34000015258789,-0.09200000762939453,99.31034088134766
4,TO,csv,100,100,13.942999839782715,13.34000015258789,0.6029996871948242,104.5202407836914
5,TO,csv,100,100,13.342000007629395,13.34000015258789,0.0019998550415039062,100.01499938964844
6,TO,csv,100,100,13.237000465393066,13.34000015258789,-0.10299968719482422,99.22789001464844
0,FROM,csv,100,1000,16.041000366210938,16.041000366210938,0.0,100.0
1,FROM,csv,100,1000,15.901000022888184,16.041000366210938,-0.1400003433227539,99.12723541259766
2,FROM,csv,100,1000,15.96500015258789,16.041000366210938,-0.07600021362304688,99.52621459960938
3,FROM,csv,100,1000,15.91100025177002,16.041000366210938,-0.13000011444091797,99.1895751953125
4,FROM,csv,100,1000,16.666000366210938,16.041000366210938,0.625,103.8962631225586
5,FROM,csv,100,1000,16.04599952697754,16.041000366210938,0.0049991607666015625,100.03115844726562
6,FROM,csv,100,1000,15.982000350952148,16.041000366210938,-0.05900001525878906,99.63219451904297
0,TO,csv,100,1000,14.817000389099121,14.817000389099121,0.0,100.0
1,TO,csv,100,1000,14.824999809265137,14.817000389099121,0.007999420166015625,100.05399322509766
2,TO,csv,100,1000,14.881999969482422,14.817000389099121,0.06499958038330078,100.43867492675781
3,TO,csv,100,1000,14.812000274658203,14.817000389099121,-0.005000114440917969,99.96625518798828
4,TO,csv,100,1000,15.557999610900879,14.817000389099121,0.7409992218017578,105.00100708007812
5,TO,csv,100,1000,14.96500015258789,14.817000389099121,0.14799976348876953,100.99885559082031
6,TO,csv,100,1000,14.859999656677246,14.817000389099121,0.042999267578125,100.29020690917969
0,FROM,csv,100,10000,33.67250061035156,33.67250061035156,0.0,100.0
1,FROM,csv,100,10000,33.73099899291992,33.67250061035156,0.058498382568359375,100.17372131347656
2,FROM,csv,100,10000,33.75849914550781,33.67250061035156,0.08599853515625,100.2553939819336
3,FROM,csv,100,10000,33.89099884033203,33.67250061035156,0.21849822998046875,100.64889526367188
4,FROM,csv,100,10000,34.55550003051758,33.67250061035156,0.8829994201660156,102.622314453125
5,FROM,csv,100,10000,33.87200164794922,33.67250061035156,0.19950103759765625,100.59246826171875
6,FROM,csv,100,10000,33.78950119018555,33.67250061035156,0.11700057983398438,100.34747314453125
0,TO,csv,100,10000,30.88599967956543,30.88599967956543,0.0,100.0
1,TO,csv,100,10000,30.55500030517578,30.88599967956543,-0.33099937438964844,98.9283218383789
2,TO,csv,100,10000,30.74650001525879,30.88599967956543,-0.13949966430664062,99.54833984375
3,TO,csv,100,10000,30.512500762939453,30.88599967956543,-0.37349891662597656,98.79071807861328
4,TO,csv,100,10000,31.254499435424805,30.88599967956543,0.368499755859375,101.1930923461914
5,TO,csv,100,10000,30.942501068115234,30.88599967956543,0.05650138854980469,100.18293762207031
6,TO,csv,100,10000,31.070999145507812,30.88599967956543,0.1849994659423828,100.5989761352539
0,FROM,csv,100,100000,209.44700622558594,209.44700622558594,0.0,100.0
1,FROM,csv,100,100000,210.281005859375,209.44700622558594,0.8339996337890625,100.398193359375
2,FROM,csv,100,100000,211.6909942626953,209.44700622558594,2.243988037109375,101.07138061523438
3,FROM,csv,100,100000,212.5240020751953,209.44700622558594,3.076995849609375,101.46910095214844
4,FROM,csv,100,100000,214.56500244140625,209.44700622558594,5.1179962158203125,102.44357299804688
5,FROM,csv,100,100000,211.677001953125,209.44700622558594,2.2299957275390625,101.06470489501953
6,FROM,csv,100,100000,210.63400268554688,209.44700622558594,1.1869964599609375,100.56673431396484
0,TO,csv,100,100000,190.36099243164062,190.36099243164062,0.0,100.0
1,TO,csv,100,100000,188.76600646972656,190.36099243164062,-1.5949859619140625,99.16212463378906
2,TO,csv,100,100000,189.13400268554688,190.36099243164062,-1.22698974609375,99.35543823242188
3,TO,csv,100,100000,189.04800415039062,190.36099243164062,-1.31298828125,99.31026458740234
4,TO,csv,100,100000,191.43299865722656,190.36099243164062,1.0720062255859375,100.56314086914062
5,TO,csv,100,100000,192.406005859375,190.36099243164062,2.045013427734375,101.07427978515625
6,TO,csv,100,100000,192.57000732421875,190.36099243164062,2.209014892578125,101.16043090820312
0,FROM,csv,100,1000000,1984.6419677734375,1984.6419677734375,0.0,100.0
1,FROM,csv,100,1000000,1976.4129638671875,1984.6419677734375,-8.22900390625,99.58536529541016
2,FROM,csv,100,1000000,1985.5889892578125,1984.6419677734375,0.947021484375,100.04772186279297
3,FROM,csv,100,1000000,1995.5389404296875,1984.6419677734375,10.89697265625,100.54906463623047
4,FROM,csv,100,1000000,1989.862060546875,1984.6419677734375,5.2200927734375,100.26302337646484
5,FROM,csv,100,1000000,1986.64794921875,1984.6419677734375,2.0059814453125,100.10107421875
6,FROM,csv,100,1000000,2001.4329833984375,1984.6419677734375,16.791015625,100.84605407714844
0,TO,csv,100,1000000,1769.8160400390625,1769.8160400390625,0.0,100.0
1,TO,csv,100,1000000,1758.2869873046875,1769.8160400390625,-11.529052734375,99.34857177734375
2,TO,csv,100,1000000,1752.718994140625,1769.8160400390625,-17.0970458984375,99.03396606445312
3,TO,csv,100,1000000,1735.5460205078125,1769.8160400390625,-34.27001953125,98.06364440917969
4,TO,csv,100,1000000,1735.7919921875,1769.8160400390625,-34.0240478515625,98.0775375366211
5,TO,csv,100,1000000,1768.4749755859375,1769.8160400390625,-1.341064453125,99.92422485351562
6,TO,csv,100,1000000,1762.3699951171875,1769.8160400390625,-7.446044921875,99.57927703857422
0,FROM,text,1,10,13.769000053405762,13.769000053405762,0.0,100.0
1,FROM,text,1,10,14.201000213623047,13.769000053405762,0.43200016021728516,103.13748168945312
2,FROM,text,1,10,14.402999877929688,13.769000053405762,0.6339998245239258,104.60454559326172
3,FROM,text,1,10,13.937999725341797,13.769000053405762,0.16899967193603516,101.2273941040039
4,FROM,text,1,10,13.39900016784668,13.769000053405762,-0.36999988555908203,97.31280517578125
5,FROM,text,1,10,14.180999755859375,13.769000053405762,0.4119997024536133,102.99222564697266
6,FROM,text,1,10,14.265999794006348,13.769000053405762,0.49699974060058594,103.60955047607422
0,TO,text,1,10,13.8149995803833,13.8149995803833,0.0,100.0
1,TO,text,1,10,13.866000175476074,13.8149995803833,0.05100059509277344,100.36917114257812
2,TO,text,1,10,14.229999542236328,13.8149995803833,0.41499996185302734,103.00398254394531
3,TO,text,1,10,14.371000289916992,13.8149995803833,0.5560007095336914,104.02461242675781
4,TO,text,1,10,13.29800033569336,13.8149995803833,-0.5169992446899414,96.25769805908203
5,TO,text,1,10,14.281999588012695,13.8149995803833,0.46700000762939453,103.38037872314453
6,TO,text,1,10,14.114999771118164,13.8149995803833,0.3000001907348633,102.17155456542969
0,FROM,text,1,100,13.458000183105469,13.458000183105469,0.0,100.0
1,FROM,text,1,100,14.434000015258789,13.458000183105469,0.9759998321533203,107.25218963623047
2,FROM,text,1,100,13.543000221252441,13.458000183105469,0.08500003814697266,100.631591796875
3,FROM,text,1,100,13.07800006866455,13.458000183105469,-0.38000011444091797,97.17639923095703
4,FROM,text,1,100,13.413999557495117,13.458000183105469,-0.04400062561035156,99.67304992675781
5,FROM,text,1,100,14.309000015258789,13.458000183105469,0.8509998321533203,106.32337188720703
6,FROM,text,1,100,14.303999900817871,13.458000183105469,0.8459997177124023,106.28621673583984
0,TO,text,1,100,13.064000129699707,13.064000129699707,0.0,100.0
1,TO,text,1,100,14.107999801635742,13.064000129699707,1.0439996719360352,107.99142456054688
2,TO,text,1,100,13.782999992370605,13.064000129699707,0.7189998626708984,105.50367736816406
3,TO,text,1,100,13.303999900817871,13.064000129699707,0.23999977111816406,101.83711242675781
4,TO,text,1,100,13.10099983215332,13.064000129699707,0.03699970245361328,100.28321838378906
5,TO,text,1,100,13.901000022888184,13.064000129699707,0.8369998931884766,106.40691375732422
6,TO,text,1,100,14.215999603271484,13.064000129699707,1.1519994735717773,108.81812286376953
0,FROM,text,1,1000,15.234000205993652,15.234000205993652,0.0,100.0
1,FROM,text,1,1000,16.202999114990234,15.234000205993652,0.968998908996582,106.36077117919922
2,FROM,text,1,1000,15.526000022888184,15.234000205993652,0.29199981689453125,101.91676330566406
3,FROM,text,1,1000,16.03499984741211,15.234000205993652,0.800999641418457,105.25797271728516
4,FROM,text,1,1000,15.571999549865723,15.234000205993652,0.3379993438720703,102.21871185302734
5,FROM,text,1,1000,16.542999267578125,15.234000205993652,1.3089990615844727,108.59262084960938
6,FROM,text,1,1000,15.46399974822998,15.234000205993652,0.22999954223632812,101.50977325439453
0,TO,text,1,1000,13.163000106811523,13.163000106811523,0.0,100.0
1,TO,text,1,1000,13.918999671936035,13.163000106811523,0.7559995651245117,105.74337005615234
2,TO,text,1,1000,12.986000061035156,13.163000106811523,-0.1770000457763672,98.65531921386719
3,TO,text,1,1000,13.039999961853027,13.163000106811523,-0.1230001449584961,99.06555938720703
4,TO,text,1,1000,13.138999938964844,13.163000106811523,-0.024000167846679688,99.81767272949219
5,TO,text,1,1000,14.157999992370605,13.163000106811523,0.994999885559082,107.5590591430664
6,TO,text,1,1000,13.024999618530273,13.163000106811523,-0.13800048828125,98.95159912109375
0,FROM,text,1,10000,16.856998443603516,16.856998443603516,0.0,100.0
1,FROM,text,1,10000,15.743499755859375,16.856998443603516,-1.1134986877441406,93.39443969726562
2,FROM,text,1,10000,16.687000274658203,16.856998443603516,-0.1699981689453125,98.99152374267578
3,FROM,text,1,10000,16.79399871826172,16.856998443603516,-0.06299972534179688,99.62626647949219
4,FROM,text,1,10000,16.017499923706055,16.856998443603516,-0.8394985198974609,95.01988220214844
5,FROM,text,1,10000,17.142501831054688,16.856998443603516,0.2855033874511719,101.69367980957031
6,FROM,text,1,10000,16.564998626708984,16.856998443603516,-0.29199981689453125,98.26778411865234
0,TO,text,1,10000,14.586999893188477,14.586999893188477,0.0,100.0
1,TO,text,1,10000,13.75,14.586999893188477,-0.8369998931884766,94.26201629638672
2,TO,text,1,10000,14.321500778198242,14.586999893188477,-0.2654991149902344,98.17989349365234
3,TO,text,1,10000,14.467000007629395,14.586999893188477,-0.11999988555908203,99.1773452758789
4,TO,text,1,10000,13.881000518798828,14.586999893188477,-0.7059993743896484,95.16007995605469
5,TO,text,1,10000,14.953499794006348,14.586999893188477,0.3664999008178711,102.51251220703125
6,TO,text,1,10000,14.104499816894531,14.586999893188477,-0.4825000762939453,96.6922607421875
0,FROM,text,1,100000,22.555999755859375,22.555999755859375,0.0,100.0
1,FROM,text,1,100000,22.099000930786133,22.555999755859375,-0.4569988250732422,97.97393798828125
2,FROM,text,1,100000,22.604999542236328,22.555999755859375,0.048999786376953125,100.21723175048828
3,FROM,text,1,100000,22.757999420166016,22.555999755859375,0.20199966430664062,100.89554595947266
4,FROM,text,1,100000,21.474000930786133,22.555999755859375,-1.0819988250732422,95.20305633544922
5,FROM,text,1,100000,21.691999435424805,22.555999755859375,-0.8640003204345703,96.1695327758789
6,FROM,text,1,100000,22.534000396728516,22.555999755859375,-0.021999359130859375,99.9024658203125
0,TO,text,1,100000,22.172000885009766,22.172000885009766,0.0,100.0
1,TO,text,1,100000,21.041000366210938,22.172000885009766,-1.1310005187988281,94.89897155761719
2,TO,text,1,100000,21.742000579833984,22.172000885009766,-0.43000030517578125,98.06061553955078
3,TO,text,1,100000,21.83099937438965,22.172000885009766,-0.3410015106201172,98.4620132446289
4,TO,text,1,100000,21.30900001525879,22.172000885009766,-0.8630008697509766,96.10769653320312
5,TO,text,1,100000,22.224000930786133,22.172000885009766,0.05200004577636719,100.23453521728516
6,TO,text,1,100000,21.777999877929688,22.172000885009766,-0.3940010070800781,98.22297668457031
0,FROM,text,1,1000000,77.38400268554688,77.38400268554688,0.0,100.0
1,FROM,text,1,1000000,77.99299621582031,77.38400268554688,0.6089935302734375,100.78697204589844
2,FROM,text,1,1000000,78.85099792480469,77.38400268554688,1.4669952392578125,101.89573669433594
3,FROM,text,1,1000000,80.00800323486328,77.38400268554688,2.6240005493164062,103.39088439941406
4,FROM,text,1,1000000,75.9800033569336,77.38400268554688,-1.4039993286132812,98.1856689453125
5,FROM,text,1,1000000,77.00499725341797,77.38400268554688,-0.37900543212890625,99.5102310180664
6,FROM,text,1,1000000,78.75299835205078,77.38400268554688,1.3689956665039062,101.76908874511719
0,TO,text,1,1000000,93.88899993896484,93.88899993896484,0.0,100.0
1,TO,text,1,1000000,93.68900299072266,93.88899993896484,-0.1999969482421875,99.7869873046875
2,TO,text,1,1000000,93.26899719238281,93.88899993896484,-0.6200027465820312,99.33963775634766
3,TO,text,1,1000000,93.28199768066406,93.88899993896484,-0.6070022583007812,99.3534927368164
4,TO,text,1,1000000,92.67400360107422,93.88899993896484,-1.214996337890625,98.70592498779297
5,TO,text,1,1000000,91.08999633789062,93.88899993896484,-2.7990036010742188,97.01881408691406
6,TO,text,1,1000000,94.31700134277344,93.88899993896484,0.42800140380859375,100.45585632324219
0,FROM,text,10,10,13.02299976348877,13.02299976348877,0.0,100.0
1,FROM,text,10,10,14.15999984741211,13.02299976348877,1.1370000839233398,108.730712890625
2,FROM,text,10,10,14.274999618530273,13.02299976348877,1.251999855041504,109.61376190185547
3,FROM,text,10,10,13.11400032043457,13.02299976348877,0.09100055694580078,100.69876861572266
4,FROM,text,10,10,13.322999954223633,13.02299976348877,0.3000001907348633,102.3036117553711
5,FROM,text,10,10,13.008999824523926,13.02299976348877,-0.01399993896484375,99.89249420166016
6,FROM,text,10,10,14.128000259399414,13.02299976348877,1.1050004959106445,108.48499298095703
0,TO,text,10,10,12.730999946594238,12.730999946594238,0.0,100.0
1,TO,text,10,10,13.84000015258789,12.730999946594238,1.1090002059936523,108.71101379394531
2,TO,text,10,10,14.050000190734863,12.730999946594238,1.319000244140625,110.36054229736328
3,TO,text,10,10,13.78499984741211,12.730999946594238,1.053999900817871,108.27899932861328
4,TO,text,10,10,13.166000366210938,12.730999946594238,0.4350004196166992,103.41686248779297
5,TO,text,10,10,12.717000007629395,12.730999946594238,-0.01399993896484375,99.8900375366211
6,TO,text,10,10,14.008000373840332,12.730999946594238,1.2770004272460938,110.0306396484375
0,FROM,text,10,100,13.505000114440918,13.505000114440918,0.0,100.0
1,FROM,text,10,100,14.144000053405762,13.505000114440918,0.6389999389648438,104.73158264160156
2,FROM,text,10,100,13.149999618530273,13.505000114440918,-0.35500049591064453,97.371337890625
3,FROM,text,10,100,13.175999641418457,13.505000114440918,-0.32900047302246094,97.5638656616211
4,FROM,text,10,100,13.482999801635742,13.505000114440918,-0.02200031280517578,99.83709716796875
5,FROM,text,10,100,13.128000259399414,13.505000114440918,-0.3769998550415039,97.20844268798828
6,FROM,text,10,100,14.383000373840332,13.505000114440918,0.8780002593994141,106.50129699707031
0,TO,text,10,100,12.914999961853027,12.914999961853027,0.0,100.0
1,TO,text,10,100,14.041000366210938,12.914999961853027,1.1260004043579102,108.71855163574219
2,TO,text,10,100,12.824000358581543,12.914999961853027,-0.09099960327148438,99.29539489746094
3,TO,text,10,100,12.744999885559082,12.914999961853027,-0.1700000762939453,98.68370056152344
4,TO,text,10,100,13.065999984741211,12.914999961853027,0.1510000228881836,101.16918182373047
5,TO,text,10,100,12.935999870300293,12.914999961853027,0.020999908447265625,100.16259765625
6,TO,text,10,100,14.130999565124512,12.914999961853027,1.2159996032714844,109.41539764404297
0,FROM,text,10,1000,15.50100040435791,15.50100040435791,0.0,100.0
1,FROM,text,10,1000,15.772000312805176,15.50100040435791,0.2709999084472656,101.74827575683594
2,FROM,text,10,1000,15.604000091552734,15.50100040435791,0.10299968719482422,100.66447448730469
3,FROM,text,10,1000,15.45199966430664,15.50100040435791,-0.04900074005126953,99.68388366699219
4,FROM,text,10,1000,15.687000274658203,15.50100040435791,0.18599987030029297,101.1999282836914
5,FROM,text,10,1000,15.5600004196167,15.50100040435791,0.05900001525878906,100.38062286376953
6,FROM,text,10,1000,15.380000114440918,15.50100040435791,-0.12100028991699219,99.21940612792969
0,TO,text,10,1000,12.982999801635742,12.982999801635742,0.0,100.0
1,TO,text,10,1000,12.91100025177002,12.982999801635742,-0.07199954986572266,99.4454345703125
2,TO,text,10,1000,13.081000328063965,12.982999801635742,0.09800052642822266,100.75483703613281
3,TO,text,10,1000,13.036999702453613,12.982999801635742,0.053999900817871094,100.41593170166016
4,TO,text,10,1000,13.232999801635742,12.982999801635742,0.25,101.92559814453125
5,TO,text,10,1000,12.916000366210938,12.982999801635742,-0.06699943542480469,99.48394012451172
6,TO,text,10,1000,13.187999725341797,12.982999801635742,0.2049999237060547,101.57898712158203
0,FROM,text,10,10000,17.1614990234375,17.1614990234375,0.0,100.0
1,FROM,text,10,10000,17.180999755859375,17.1614990234375,0.019500732421875,100.11363220214844
2,FROM,text,10,10000,17.289501190185547,17.1614990234375,0.12800216674804688,100.74586486816406
3,FROM,text,10,10000,17.407501220703125,17.1614990234375,0.246002197265625,101.43345642089844
4,FROM,text,10,10000,17.475500106811523,17.1614990234375,0.31400108337402344,101.82968139648438
5,FROM,text,10,10000,17.594499588012695,17.1614990234375,0.4330005645751953,102.52308654785156
6,FROM,text,10,10000,17.102500915527344,17.1614990234375,-0.05899810791015625,99.65621948242188
0,TO,text,10,10000,15.088500022888184,15.088500022888184,0.0,100.0
1,TO,text,10,10000,14.866000175476074,15.088500022888184,-0.22249984741210938,98.5253677368164
2,TO,text,10,10000,14.911499977111816,15.088500022888184,-0.1770000457763672,98.82691955566406
3,TO,text,10,10000,15.024999618530273,15.088500022888184,-0.06350040435791016,99.57914733886719
4,TO,text,10,10000,15.13800048828125,15.088500022888184,0.049500465393066406,100.32806396484375
5,TO,text,10,10000,15.316499710083008,15.088500022888184,0.22799968719482422,101.5110855102539
6,TO,text,10,10000,14.802999496459961,15.088500022888184,-0.28550052642822266,98.10782623291016
0,FROM,text,10,100000,35.22999954223633,35.22999954223633,0.0,100.0
1,FROM,text,10,100000,34.93199920654297,35.22999954223633,-0.2980003356933594,99.15412902832031
2,FROM,text,10,100000,35.17399978637695,35.22999954223633,-0.055999755859375,99.84104919433594
3,FROM,text,10,100000,35.10900115966797,35.22999954223633,-0.12099838256835938,99.65654754638672
4,FROM,text,10,100000,35.340999603271484,35.22999954223633,0.11100006103515625,100.31507110595703
5,FROM,text,10,100000,35.18600082397461,35.22999954223633,-0.04399871826171875,99.87510681152344
6,FROM,text,10,100000,35.104000091552734,35.22999954223633,-0.12599945068359375,99.6423568725586
0,TO,text,10,100000,34.05699920654297,34.05699920654297,0.0,100.0
1,TO,text,10,100000,34.13199996948242,34.05699920654297,0.07500076293945312,100.22023010253906
2,TO,text,10,100000,33.90800094604492,34.05699920654297,-0.14899826049804688,99.5625
3,TO,text,10,100000,34.125,34.05699920654297,0.06800079345703125,100.19966125488281
4,TO,text,10,100000,34.35200119018555,34.05699920654297,0.2950019836425781,100.86619567871094
5,TO,text,10,100000,34.1879997253418,34.05699920654297,0.13100051879882812,100.38465118408203
6,TO,text,10,100000,34.33700180053711,34.05699920654297,0.2800025939941406,100.82215881347656
0,FROM,text,10,1000000,211.39100646972656,211.39100646972656,0.0,100.0
1,FROM,text,10,1000000,211.64199829101562,211.39100646972656,0.2509918212890625,100.11872863769531
2,FROM,text,10,1000000,210.7239990234375,211.39100646972656,-0.6670074462890625,99.68446350097656
3,FROM,text,10,1000000,213.1199951171875,211.39100646972656,1.7289886474609375,100.81790924072266
4,FROM,text,10,1000000,212.1649932861328,211.39100646972656,0.77398681640625,100.36614227294922
5,FROM,text,10,1000000,212.3280029296875,211.39100646972656,0.9369964599609375,100.44325256347656
6,FROM,text,10,1000000,214.13600158691406,211.39100646972656,2.7449951171875,101.29853820800781
0,TO,text,10,1000000,220.44700622558594,220.44700622558594,0.0,100.0
1,TO,text,10,1000000,221.54600524902344,220.44700622558594,1.0989990234375,100.49853515625
2,TO,text,10,1000000,221.20899963378906,220.44700622558594,0.761993408203125,100.34565734863281
3,TO,text,10,1000000,223.18699645996094,220.44700622558594,2.739990234375,101.242919921875
4,TO,text,10,1000000,223.52200317382812,220.44700622558594,3.0749969482421875,101.39488983154297
5,TO,text,10,1000000,221.44000244140625,220.44700622558594,0.9929962158203125,100.45044708251953
6,TO,text,10,1000000,223.74600219726562,220.44700622558594,3.2989959716796875,101.49650573730469
0,FROM,text,100,10,13.385000228881836,13.385000228881836,0.0,100.0
1,FROM,text,100,10,13.446999549865723,13.385000228881836,0.06199932098388672,100.46319580078125
2,FROM,text,100,10,13.605999946594238,13.385000228881836,0.22099971771240234,101.65109252929688
3,FROM,text,100,10,13.440999984741211,13.385000228881836,0.055999755859375,100.41838073730469
4,FROM,text,100,10,13.35200023651123,13.385000228881836,-0.03299999237060547,99.75345611572266
5,FROM,text,100,10,13.539999961853027,13.385000228881836,0.1549997329711914,101.15801239013672
6,FROM,text,100,10,13.435999870300293,13.385000228881836,0.05099964141845703,100.38101959228516
0,TO,text,100,10,13.1850004196167,13.1850004196167,0.0,100.0
1,TO,text,100,10,13.090999603271484,13.1850004196167,-0.09400081634521484,99.28706359863281
2,TO,text,100,10,12.76200008392334,13.1850004196167,-0.4230003356933594,96.79180145263672
3,TO,text,100,10,13.562999725341797,13.1850004196167,0.37799930572509766,102.86688995361328
4,TO,text,100,10,13.135000228881836,13.1850004196167,-0.05000019073486328,99.62078094482422
5,TO,text,100,10,13.223999977111816,13.1850004196167,0.03899955749511719,100.29578399658203
6,TO,text,100,10,13.168000221252441,13.1850004196167,-0.017000198364257812,99.87106323242188
0,FROM,text,100,100,13.800999641418457,13.800999641418457,0.0,100.0
1,FROM,text,100,100,13.746999740600586,13.800999641418457,-0.053999900817871094,99.60872650146484
2,FROM,text,100,100,13.75,13.800999641418457,-0.05099964141845703,99.63046264648438
3,FROM,text,100,100,13.795999526977539,13.800999641418457,-0.005000114440917969,99.96377563476562
4,FROM,text,100,100,13.710000038146973,13.800999641418457,-0.09099960327148438,99.34062957763672
5,FROM,text,100,100,13.73799991607666,13.800999641418457,-0.06299972534179688,99.54351043701172
6,FROM,text,100,100,13.710000038146973,13.800999641418457,-0.09099960327148438,99.34062957763672
0,TO,text,100,100,13.3100004196167,13.3100004196167,0.0,100.0
1,TO,text,100,100,13.187999725341797,13.3100004196167,-0.12200069427490234,99.08338928222656
2,TO,text,100,100,13.461999893188477,13.3100004196167,0.15199947357177734,101.1419906616211
3,TO,text,100,100,13.24899959564209,13.3100004196167,-0.061000823974609375,99.54169464111328
4,TO,text,100,100,13.187999725341797,13.3100004196167,-0.12200069427490234,99.08338928222656
5,TO,text,100,100,13.315999984741211,13.3100004196167,0.005999565124511719,100.04507446289062
6,TO,text,100,100,13.364999771118164,13.3100004196167,0.054999351501464844,100.41321563720703
0,FROM,text,100,1000,15.538000106811523,15.538000106811523,0.0,100.0
1,FROM,text,100,1000,15.553999900817871,15.538000106811523,0.015999794006347656,100.10297393798828
2,FROM,text,100,1000,15.567999839782715,15.538000106811523,0.029999732971191406,100.19306945800781
3,FROM,text,100,1000,15.5,15.538000106811523,-0.03800010681152344,99.75543975830078
4,FROM,text,100,1000,15.557000160217285,15.538000106811523,0.01900005340576172,100.12228393554688
5,FROM,text,100,1000,15.6850004196167,15.538000106811523,0.14700031280517578,100.9460678100586
6,FROM,text,100,1000,15.609999656677246,15.538000106811523,0.07199954986572266,100.46337890625
0,TO,text,100,1000,14.57800006866455,14.57800006866455,0.0,100.0
1,TO,text,100,1000,14.565999984741211,14.57800006866455,-0.012000083923339844,99.91768646240234
2,TO,text,100,1000,14.545999526977539,14.57800006866455,-0.03200054168701172,99.78048706054688
3,TO,text,100,1000,14.621000289916992,14.57800006866455,0.043000221252441406,100.29496765136719
4,TO,text,100,1000,14.581000328063965,14.57800006866455,0.0030002593994140625,100.02057647705078
5,TO,text,100,1000,14.652000427246094,14.57800006866455,0.07400035858154297,100.50761413574219
6,TO,text,100,1000,14.61400032043457,14.57800006866455,0.03600025177001953,100.24695587158203
0,FROM,text,100,10000,29.917499542236328,29.917499542236328,0.0,100.0
1,FROM,text,100,10000,29.832000732421875,29.917499542236328,-0.08549880981445312,99.71421813964844
2,FROM,text,100,10000,29.85449981689453,29.917499542236328,-0.06299972534179688,99.78942108154297
3,FROM,text,100,10000,29.98900032043457,29.917499542236328,0.07150077819824219,100.2389907836914
4,FROM,text,100,10000,29.929500579833984,29.917499542236328,0.01200103759765625,100.04011535644531
5,FROM,text,100,10000,29.87849998474121,29.917499542236328,-0.03899955749511719,99.86964416503906
6,FROM,text,100,10000,29.836000442504883,29.917499542236328,-0.08149909973144531,99.72759246826172
0,TO,text,100,10000,27.958999633789062,27.958999633789062,0.0,100.0
1,TO,text,100,10000,27.842998504638672,27.958999633789062,-0.11600112915039062,99.5851058959961
2,TO,text,100,10000,27.89699935913086,27.958999633789062,-0.062000274658203125,99.77824401855469
3,TO,text,100,10000,27.789501190185547,27.958999633789062,-0.16949844360351562,99.39376068115234
4,TO,text,100,10000,27.736000061035156,27.958999633789062,-0.22299957275390625,99.20240783691406
5,TO,text,100,10000,27.95549964904785,27.958999633789062,-0.0034999847412109375,99.98748016357422
6,TO,text,100,10000,27.85849952697754,27.958999633789062,-0.10050010681152344,99.64054107666016
0,FROM,text,100,100000,171.50999450683594,171.50999450683594,0.0,100.0
1,FROM,text,100,100000,171.36500549316406,171.50999450683594,-0.144989013671875,99.91546630859375
2,FROM,text,100,100000,171.1510009765625,171.50999450683594,-0.3589935302734375,99.79068756103516
3,FROM,text,100,100000,171.71299743652344,171.50999450683594,0.2030029296875,100.11836242675781
4,FROM,text,100,100000,171.71200561523438,171.50999450683594,0.2020111083984375,100.11778259277344
5,FROM,text,100,100000,171.0850067138672,171.50999450683594,-0.42498779296875,99.75220489501953
6,FROM,text,100,100000,173.59800720214844,171.50999450683594,2.0880126953125,101.21742248535156
0,TO,text,100,100000,158.4969940185547,158.4969940185547,0.0,100.0
1,TO,text,100,100000,159.46200561523438,158.4969940185547,0.9650115966796875,100.60884857177734
2,TO,text,100,100000,159.26600646972656,158.4969940185547,0.769012451171875,100.48519134521484
3,TO,text,100,100000,160.48300170898438,158.4969940185547,1.9860076904296875,101.25302124023438
4,TO,text,100,100000,160.4739990234375,158.4969940185547,1.9770050048828125,101.24734497070312
5,TO,text,100,100000,160.1540069580078,158.4969940185547,1.657012939453125,101.04545593261719
6,TO,text,100,100000,161.03199768066406,158.4969940185547,2.535003662109375,101.59941101074219
0,FROM,text,100,1000000,1580.781005859375,1580.781005859375,0.0,100.0
1,FROM,text,100,1000000,1581.64501953125,1580.781005859375,0.864013671875,100.05465698242188
2,FROM,text,100,1000000,1579.0860595703125,1580.781005859375,-1.6949462890625,99.89277648925781
3,FROM,text,100,1000000,1584.39697265625,1580.781005859375,3.615966796875,100.22875213623047
4,FROM,text,100,1000000,1580.8489990234375,1580.781005859375,0.0679931640625,100.00430297851562
5,FROM,text,100,1000000,1580.2359619140625,1580.781005859375,-0.5450439453125,99.96551513671875
6,FROM,text,100,1000000,1595.02294921875,1580.781005859375,14.241943359375,100.90094757080078
0,TO,text,100,1000000,1453.75,1453.75,0.0,100.0
1,TO,text,100,1000000,1467.345947265625,1453.75,13.595947265625,100.93523406982422
2,TO,text,100,1000000,1467.9010009765625,1453.75,14.1510009765625,100.97341918945312
3,TO,text,100,1000000,1472.8160400390625,1453.75,19.0660400390625,101.31150817871094
4,TO,text,100,1000000,1468.52294921875,1453.75,14.77294921875,101.01619720458984
5,TO,text,100,1000000,1469.5989990234375,1453.75,15.8489990234375,101.09021759033203
6,TO,text,100,1000000,1475.1009521484375,1453.75,21.3509521484375,101.46868133544922
version,type,format,n_columns,n_rows,runtime,base_runtime,diff_runtime,diff_percentage
0,FROM,binary,1,10,13.128000259399414,13.128000259399414,0.0,100.0
1,FROM,binary,1,10,13.163000106811523,13.128000259399414,0.034999847412109375,100.2666015625
2,FROM,binary,1,10,13.23900032043457,13.128000259399414,0.11100006103515625,100.84551239013672
3,FROM,binary,1,10,13.279000282287598,13.128000259399414,0.1510000228881836,101.15021514892578
4,FROM,binary,1,10,13.286999702453613,13.128000259399414,0.15899944305419922,101.21114349365234
5,FROM,binary,1,10,13.20199966430664,13.128000259399414,0.07399940490722656,100.56368255615234
6,FROM,binary,1,10,13.279999732971191,13.128000259399414,0.15199947357177734,101.15782928466797
0,TO,binary,1,10,12.864999771118164,12.864999771118164,0.0,100.0
1,TO,binary,1,10,12.918999671936035,12.864999771118164,0.053999900817871094,100.41974639892578
2,TO,binary,1,10,13.01200008392334,12.864999771118164,0.14700031280517578,101.14263153076172
3,TO,binary,1,10,12.98799991607666,12.864999771118164,0.1230001449584961,100.95608520507812
4,TO,binary,1,10,12.982000350952148,12.864999771118164,0.11700057983398438,100.9094467163086
5,TO,binary,1,10,12.946999549865723,12.864999771118164,0.0819997787475586,100.63739013671875
6,TO,binary,1,10,12.989999771118164,12.864999771118164,0.125,100.97162628173828
0,FROM,binary,1,100,13.187999725341797,13.187999725341797,0.0,100.0
1,FROM,binary,1,100,13.333999633789062,13.187999725341797,0.14599990844726562,101.10706329345703
2,FROM,binary,1,100,13.321999549865723,13.187999725341797,0.13399982452392578,101.01606750488281
3,FROM,binary,1,100,13.3100004196167,13.187999725341797,0.12200069427490234,100.92508697509766
4,FROM,binary,1,100,13.307000160217285,13.187999725341797,0.11900043487548828,100.90234375
5,FROM,binary,1,100,13.39900016784668,13.187999725341797,0.2110004425048828,101.59994506835938
6,FROM,binary,1,100,13.289999961853027,13.187999725341797,0.10200023651123047,100.77342987060547
0,TO,binary,1,100,12.86400032043457,12.86400032043457,0.0,100.0
1,TO,binary,1,100,12.906000137329102,12.86400032043457,0.04199981689453125,100.32649230957031
2,TO,binary,1,100,12.996000289916992,12.86400032043457,0.13199996948242188,101.02611541748047
3,TO,binary,1,100,12.982999801635742,12.86400032043457,0.11899948120117188,100.92506408691406
4,TO,binary,1,100,13.017999649047852,12.86400032043457,0.15399932861328125,101.19713592529297
5,TO,binary,1,100,13.020000457763672,12.86400032043457,0.15600013732910156,101.21269226074219
6,TO,binary,1,100,12.991000175476074,12.86400032043457,0.1269998550415039,100.98725891113281
0,FROM,binary,1,1000,15.201000213623047,15.201000213623047,0.0,100.0
1,FROM,binary,1,1000,15.446000099182129,15.201000213623047,0.24499988555908203,101.61173248291016
2,FROM,binary,1,1000,15.232000350952148,15.201000213623047,0.031000137329101562,100.20393371582031
3,FROM,binary,1,1000,15.447999954223633,15.201000213623047,0.24699974060058594,101.62489318847656
4,FROM,binary,1,1000,15.414999961853027,15.201000213623047,0.21399974822998047,101.40779876708984
5,FROM,binary,1,1000,15.371999740600586,15.201000213623047,0.17099952697753906,101.12491607666016
6,FROM,binary,1,1000,15.329000473022461,15.201000213623047,0.12800025939941406,100.84204864501953
0,TO,binary,1,1000,13.005000114440918,13.005000114440918,0.0,100.0
1,TO,binary,1,1000,13.069000244140625,13.005000114440918,0.06400012969970703,100.49211883544922
2,TO,binary,1,1000,13.038000106811523,13.005000114440918,0.03299999237060547,100.25374603271484
3,TO,binary,1,1000,13.121999740600586,13.005000114440918,0.11699962615966797,100.89965057373047
4,TO,binary,1,1000,13.0600004196167,13.005000114440918,0.05500030517578125,100.42292022705078
5,TO,binary,1,1000,13.088000297546387,13.005000114440918,0.08300018310546875,100.63822174072266
6,TO,binary,1,1000,13.048999786376953,13.005000114440918,0.043999671936035156,100.33832550048828
0,FROM,binary,1,10000,15.692500114440918,15.692500114440918,0.0,100.0
1,FROM,binary,1,10000,15.758000373840332,15.692500114440918,0.06550025939941406,100.41739654541016
2,FROM,binary,1,10000,15.827499389648438,15.692500114440918,0.13499927520751953,100.86027526855469
3,FROM,binary,1,10000,15.843000411987305,15.692500114440918,0.15050029754638672,100.95906066894531
4,FROM,binary,1,10000,15.835500717163086,15.692500114440918,0.14300060272216797,100.91127014160156
5,FROM,binary,1,10000,15.767000198364258,15.692500114440918,0.07450008392333984,100.4747543334961
6,FROM,binary,1,10000,15.79699993133545,15.692500114440918,0.10449981689453125,100.66592407226562
0,TO,binary,1,10000,13.656999588012695,13.656999588012695,0.0,100.0
1,TO,binary,1,10000,13.887499809265137,13.656999588012695,0.2305002212524414,101.68777465820312
2,TO,binary,1,10000,13.847999572753906,13.656999588012695,0.19099998474121094,101.39855194091797
3,TO,binary,1,10000,13.883499145507812,13.656999588012695,0.2264995574951172,101.65848541259766
4,TO,binary,1,10000,13.885000228881836,13.656999588012695,0.22800064086914062,101.66947937011719
5,TO,binary,1,10000,13.912500381469727,13.656999588012695,0.25550079345703125,101.870849609375
6,TO,binary,1,10000,13.834500312805176,13.656999588012695,0.17750072479248047,101.2997055053711
0,FROM,binary,1,100000,20.256000518798828,20.256000518798828,0.0,100.0
1,FROM,binary,1,100000,20.488000869750977,20.256000518798828,0.23200035095214844,101.14533996582031
2,FROM,binary,1,100000,20.23900032043457,20.256000518798828,-0.017000198364257812,99.91606903076172
3,FROM,binary,1,100000,20.33300018310547,20.256000518798828,0.07699966430664062,100.38013458251953
4,FROM,binary,1,100000,20.23200035095215,20.256000518798828,-0.024000167846679688,99.88151550292969
5,FROM,binary,1,100000,20.152999877929688,20.256000518798828,-0.10300064086914062,99.49150848388672
6,FROM,binary,1,100000,20.160999298095703,20.256000518798828,-0.095001220703125,99.53099822998047
0,TO,binary,1,100000,21.645000457763672,21.645000457763672,0.0,100.0
1,TO,binary,1,100000,21.948999404907227,21.645000457763672,0.3039989471435547,101.40447998046875
2,TO,binary,1,100000,22.031999588012695,21.645000457763672,0.38699913024902344,101.78793334960938
3,TO,binary,1,100000,22.099000930786133,21.645000457763672,0.45400047302246094,102.09748840332031
4,TO,binary,1,100000,22.097999572753906,21.645000457763672,0.4529991149902344,102.09286499023438
5,TO,binary,1,100000,22.018999099731445,21.645000457763672,0.37399864196777344,101.7278823852539
6,TO,binary,1,100000,21.9950008392334,21.645000457763672,0.35000038146972656,101.61700439453125
0,FROM,binary,1,1000000,64.54299926757812,64.54299926757812,0.0,100.0
1,FROM,binary,1,1000000,66.40899658203125,64.54299926757812,1.865997314453125,102.8910903930664
2,FROM,binary,1,1000000,64.04499816894531,64.54299926757812,-0.4980010986328125,99.2284164428711
3,FROM,binary,1,1000000,65.14199829101562,64.54299926757812,0.5989990234375,100.92805480957031
4,FROM,binary,1,1000000,64.18000030517578,64.54299926757812,-0.36299896240234375,99.43759155273438
5,FROM,binary,1,1000000,63.59000015258789,64.54299926757812,-0.9529991149902344,98.52346801757812
6,FROM,binary,1,1000000,63.6870002746582,64.54299926757812,-0.8559989929199219,98.67375183105469
0,TO,binary,1,1000000,99.98600006103516,99.98600006103516,0.0,100.0
1,TO,binary,1,1000000,100.70099639892578,99.98600006103516,0.714996337890625,100.71510314941406
2,TO,binary,1,1000000,100.66000366210938,99.98600006103516,0.6740036010742188,100.6740951538086
3,TO,binary,1,1000000,100.73100280761719,99.98600006103516,0.7450027465820312,100.74510192871094
4,TO,binary,1,1000000,101.14299774169922,99.98600006103516,1.1569976806640625,101.15716552734375
5,TO,binary,1,1000000,100.36199951171875,99.98600006103516,0.37599945068359375,100.37606048583984
6,TO,binary,1,1000000,100.50800323486328,99.98600006103516,0.522003173828125,100.52207946777344
0,FROM,binary,10,10,13.053999900817871,13.053999900817871,0.0,100.0
1,FROM,binary,10,10,13.211999893188477,13.053999900817871,0.15799999237060547,101.21035766601562
2,FROM,binary,10,10,13.161999702453613,13.053999900817871,0.10799980163574219,100.82733917236328
3,FROM,binary,10,10,13.295999526977539,13.053999900817871,0.24199962615966797,101.85383605957031
4,FROM,binary,10,10,13.255999565124512,13.053999900817871,0.20199966430664062,101.54741668701172
5,FROM,binary,10,10,13.21500015258789,13.053999900817871,0.16100025177001953,101.23333740234375
6,FROM,binary,10,10,13.222000122070312,13.053999900817871,0.1680002212524414,101.28695678710938
0,TO,binary,10,10,12.800000190734863,12.800000190734863,0.0,100.0
1,TO,binary,10,10,12.984000205993652,12.800000190734863,0.18400001525878906,101.4375
2,TO,binary,10,10,12.944999694824219,12.800000190734863,0.14499950408935547,101.1328125
3,TO,binary,10,10,12.979000091552734,12.800000190734863,0.1789999008178711,101.39842987060547
4,TO,binary,10,10,13.145000457763672,12.800000190734863,0.3450002670288086,102.6953125
5,TO,binary,10,10,12.888999938964844,12.800000190734863,0.08899974822998047,100.6953125
6,TO,binary,10,10,12.923999786376953,12.800000190734863,0.12399959564208984,100.96874237060547
0,FROM,binary,10,100,13.27400016784668,13.27400016784668,0.0,100.0
1,FROM,binary,10,100,13.368000030517578,13.27400016784668,0.09399986267089844,100.7081527709961
2,FROM,binary,10,100,13.284000396728516,13.27400016784668,0.010000228881835938,100.0753402709961
3,FROM,binary,10,100,13.491000175476074,13.27400016784668,0.21700000762939453,101.63477325439453
4,FROM,binary,10,100,13.392999649047852,13.27400016784668,0.11899948120117188,100.89649200439453
5,FROM,binary,10,100,13.359000205993652,13.27400016784668,0.08500003814697266,100.64034271240234
6,FROM,binary,10,100,13.289999961853027,13.27400016784668,0.015999794006347656,100.12052917480469
0,TO,binary,10,100,12.899999618530273,12.899999618530273,0.0,100.0
1,TO,binary,10,100,12.850000381469727,12.899999618530273,-0.049999237060546875,99.61241149902344
2,TO,binary,10,100,12.944999694824219,12.899999618530273,0.04500007629394531,100.34883880615234
3,TO,binary,10,100,13.003999710083008,12.899999618530273,0.10400009155273438,100.80619812011719
4,TO,binary,10,100,13.050000190734863,12.899999618530273,0.15000057220458984,101.16278839111328
5,TO,binary,10,100,13.027000427246094,12.899999618530273,0.1270008087158203,100.98450469970703
6,TO,binary,10,100,12.89900016784668,12.899999618530273,-0.00099945068359375,99.99224853515625
0,FROM,binary,10,1000,15.343000411987305,15.343000411987305,0.0,100.0
1,FROM,binary,10,1000,15.46399974822998,15.343000411987305,0.12099933624267578,100.78862762451172
2,FROM,binary,10,1000,15.493000030517578,15.343000411987305,0.14999961853027344,100.97764587402344
3,FROM,binary,10,1000,15.479000091552734,15.343000411987305,0.1359996795654297,100.88639068603516
4,FROM,binary,10,1000,15.567000389099121,15.343000411987305,0.2239999771118164,101.45994567871094
5,FROM,binary,10,1000,15.456999778747559,15.343000411987305,0.1139993667602539,100.74301147460938
6,FROM,binary,10,1000,15.52400016784668,15.343000411987305,0.180999755859375,101.17969512939453
0,TO,binary,10,1000,13.190999984741211,13.190999984741211,0.0,100.0
1,TO,binary,10,1000,13.312000274658203,13.190999984741211,0.12100028991699219,100.91728973388672
2,TO,binary,10,1000,13.196000099182129,13.190999984741211,0.005000114440917969,100.03791046142578
3,TO,binary,10,1000,13.359999656677246,13.190999984741211,0.16899967193603516,101.28118133544922
4,TO,binary,10,1000,13.32699966430664,13.190999984741211,0.1359996795654297,101.031005859375
5,TO,binary,10,1000,13.300000190734863,13.190999984741211,0.10900020599365234,100.82632446289062
6,TO,binary,10,1000,13.26099967956543,13.190999984741211,0.06999969482421875,100.5306625366211
0,FROM,binary,10,10000,16.972000122070312,16.972000122070312,0.0,100.0
1,FROM,binary,10,10000,17.145999908447266,16.972000122070312,0.17399978637695312,101.02521514892578
2,FROM,binary,10,10000,17.069000244140625,16.972000122070312,0.0970001220703125,100.57152557373047
3,FROM,binary,10,10000,17.119998931884766,16.972000122070312,0.14799880981445312,100.87201690673828
4,FROM,binary,10,10000,17.07149887084961,16.972000122070312,0.09949874877929688,100.58625030517578
5,FROM,binary,10,10000,16.997501373291016,16.972000122070312,0.025501251220703125,100.15025329589844
6,FROM,binary,10,10000,17.13450050354004,16.972000122070312,0.16250038146972656,100.95746612548828
0,TO,binary,10,10000,16.101999282836914,16.101999282836914,0.0,100.0
1,TO,binary,10,10000,16.105998992919922,16.101999282836914,0.0039997100830078125,100.02484130859375
2,TO,binary,10,10000,16.105499267578125,16.101999282836914,0.0034999847412109375,100.021728515625
3,TO,binary,10,10000,16.0885009765625,16.101999282836914,-0.013498306274414062,99.91616821289062
4,TO,binary,10,10000,16.20800018310547,16.101999282836914,0.10600090026855469,100.65830993652344
5,TO,binary,10,10000,16.075000762939453,16.101999282836914,-0.026998519897460938,99.83232879638672
6,TO,binary,10,10000,16.170499801635742,16.101999282836914,0.06850051879882812,100.42542266845703
0,FROM,binary,10,100000,32.880001068115234,32.880001068115234,0.0,100.0
1,FROM,binary,10,100000,33.98699951171875,32.880001068115234,1.1069984436035156,103.36678314208984
2,FROM,binary,10,100000,32.82899856567383,32.880001068115234,-0.05100250244140625,99.84488677978516
3,FROM,binary,10,100000,33.029998779296875,32.880001068115234,0.14999771118164062,100.4561996459961
4,FROM,binary,10,100000,32.926998138427734,32.880001068115234,0.0469970703125,100.14292907714844
5,FROM,binary,10,100000,32.891998291015625,32.880001068115234,0.011997222900390625,100.03649139404297
6,FROM,binary,10,100000,32.87799835205078,32.880001068115234,-0.002002716064453125,99.99391174316406
0,TO,binary,10,100000,44.766998291015625,44.766998291015625,0.0,100.0
1,TO,binary,10,100000,44.340999603271484,44.766998291015625,-0.4259986877441406,99.04840850830078
2,TO,binary,10,100000,44.37099838256836,44.766998291015625,-0.3959999084472656,99.11541748046875
3,TO,binary,10,100000,44.10599899291992,44.766998291015625,-0.6609992980957031,98.52346801757812
4,TO,binary,10,100000,44.35900115966797,44.766998291015625,-0.40799713134765625,99.088623046875
5,TO,binary,10,100000,44.38199996948242,44.766998291015625,-0.3849983215332031,99.1399917602539
6,TO,binary,10,100000,44.29800033569336,44.766998291015625,-0.4689979553222656,98.95236206054688
0,FROM,binary,10,1000000,187.36000061035156,187.36000061035156,0.0,100.0
1,FROM,binary,10,1000000,197.3090057373047,187.36000061035156,9.949005126953125,105.31010437011719
2,FROM,binary,10,1000000,186.29600524902344,187.36000061035156,-1.063995361328125,99.43211364746094
3,FROM,binary,10,1000000,186.69200134277344,187.36000061035156,-0.667999267578125,99.64347076416016
4,FROM,binary,10,1000000,186.16799926757812,187.36000061035156,-1.1920013427734375,99.3637924194336
5,FROM,binary,10,1000000,185.75599670410156,187.36000061035156,-1.60400390625,99.14389038085938
6,FROM,binary,10,1000000,186.6020050048828,187.36000061035156,-0.75799560546875,99.5954360961914
0,TO,binary,10,1000000,327.0580139160156,327.0580139160156,0.0,100.0
1,TO,binary,10,1000000,322.7510070800781,327.0580139160156,-4.3070068359375,98.68310546875
2,TO,binary,10,1000000,322.3059997558594,327.0580139160156,-4.75201416015625,98.54704284667969
3,TO,binary,10,1000000,321.7590026855469,327.0580139160156,-5.29901123046875,98.37979888916016
4,TO,binary,10,1000000,321.8500061035156,327.0580139160156,-5.2080078125,98.40762329101562
5,TO,binary,10,1000000,322.447998046875,327.0580139160156,-4.610015869140625,98.5904541015625
6,TO,binary,10,1000000,322.781005859375,327.0580139160156,-4.277008056640625,98.6922836303711
0,FROM,binary,100,10,13.236000061035156,13.236000061035156,0.0,100.0
1,FROM,binary,100,10,13.282999992370605,13.236000061035156,0.04699993133544922,100.35508728027344
2,FROM,binary,100,10,13.25100040435791,13.236000061035156,0.015000343322753906,100.11333465576172
3,FROM,binary,100,10,13.345000267028809,13.236000061035156,0.10900020599365234,100.8235092163086
4,FROM,binary,100,10,13.366000175476074,13.236000061035156,0.13000011444091797,100.98216247558594
5,FROM,binary,100,10,13.366999626159668,13.236000061035156,0.13099956512451172,100.9897232055664
6,FROM,binary,100,10,13.331000328063965,13.236000061035156,0.0950002670288086,100.7177505493164
0,TO,binary,100,10,12.949000358581543,12.949000358581543,0.0,100.0
1,TO,binary,100,10,12.996999740600586,12.949000358581543,0.04799938201904297,100.37068176269531
2,TO,binary,100,10,12.98799991607666,12.949000358581543,0.03899955749511719,100.30118560791016
3,TO,binary,100,10,13.097999572753906,12.949000358581543,0.14899921417236328,101.15066528320312
4,TO,binary,100,10,13.319000244140625,12.949000358581543,0.36999988555908203,102.85736083984375
5,TO,binary,100,10,13.013999938964844,12.949000358581543,0.06499958038330078,100.50196838378906
6,TO,binary,100,10,13.0,12.949000358581543,0.05099964141845703,100.39385223388672
0,FROM,binary,100,100,13.567000389099121,13.567000389099121,0.0,100.0
1,FROM,binary,100,100,13.5,13.567000389099121,-0.0670003890991211,99.50614929199219
2,FROM,binary,100,100,13.640000343322754,13.567000389099121,0.07299995422363281,100.53807830810547
3,FROM,binary,100,100,13.54699993133545,13.567000389099121,-0.020000457763671875,99.85257720947266
4,FROM,binary,100,100,13.652999877929688,13.567000389099121,0.0859994888305664,100.63388061523438
5,FROM,binary,100,100,13.513999938964844,13.567000389099121,-0.053000450134277344,99.60934448242188
6,FROM,binary,100,100,13.489999771118164,13.567000389099121,-0.07700061798095703,99.43244171142578
0,TO,binary,100,100,13.260000228881836,13.260000228881836,0.0,100.0
1,TO,binary,100,100,13.277999877929688,13.260000228881836,0.017999649047851562,100.1357421875
2,TO,binary,100,100,13.243000030517578,13.260000228881836,-0.017000198364257812,99.87178802490234
3,TO,binary,100,100,13.3100004196167,13.260000228881836,0.05000019073486328,100.37706756591797
4,TO,binary,100,100,13.26099967956543,13.260000228881836,0.00099945068359375,100.00753784179688
5,TO,binary,100,100,13.194999694824219,13.260000228881836,-0.06500053405761719,99.50979614257812
6,TO,binary,100,100,13.170000076293945,13.260000228881836,-0.09000015258789062,99.3212661743164
0,FROM,binary,100,1000,17.04400062561035,17.04400062561035,0.0,100.0
1,FROM,binary,100,1000,17.243000030517578,17.04400062561035,0.19899940490722656,101.16755676269531
2,FROM,binary,100,1000,17.083999633789062,17.04400062561035,0.03999900817871094,100.23467254638672
3,FROM,binary,100,1000,17.24799919128418,17.04400062561035,0.20399856567382812,101.1968994140625
4,FROM,binary,100,1000,17.225000381469727,17.04400062561035,0.180999755859375,101.06195068359375
5,FROM,binary,100,1000,17.05500030517578,17.04400062561035,0.010999679565429688,100.06453704833984
6,FROM,binary,100,1000,17.381000518798828,17.04400062561035,0.33699989318847656,101.97722625732422
0,TO,binary,100,1000,15.149999618530273,15.149999618530273,0.0,100.0
1,TO,binary,100,1000,15.267999649047852,15.149999618530273,0.11800003051757812,100.77887725830078
2,TO,binary,100,1000,15.142999649047852,15.149999618530273,-0.006999969482421875,99.95379638671875
3,TO,binary,100,1000,15.208000183105469,15.149999618530273,0.05800056457519531,100.38284301757812
4,TO,binary,100,1000,15.319999694824219,15.149999618530273,0.1700000762939453,101.12211608886719
5,TO,binary,100,1000,15.217000007629395,15.149999618530273,0.0670003890991211,100.44224548339844
6,TO,binary,100,1000,15.13700008392334,15.149999618530273,-0.012999534606933594,99.91419219970703
0,FROM,binary,100,10000,29.787498474121094,29.787498474121094,0.0,100.0
1,FROM,binary,100,10000,31.130001068115234,29.787498474121094,1.3425025939941406,104.5069351196289
2,FROM,binary,100,10000,29.85449981689453,29.787498474121094,0.0670013427734375,100.22493743896484
3,FROM,binary,100,10000,29.921499252319336,29.787498474121094,0.1340007781982422,100.44985961914062
4,FROM,binary,100,10000,30.02549934387207,29.787498474121094,0.23800086975097656,100.79900360107422
5,FROM,binary,100,10000,29.897499084472656,29.787498474121094,0.1100006103515625,100.3692855834961
6,FROM,binary,100,10000,29.878000259399414,29.787498474121094,0.09050178527832031,100.30382537841797
0,TO,binary,100,10000,35.19249725341797,35.19249725341797,0.0,100.0
1,TO,binary,100,10000,35.326499938964844,35.19249725341797,0.134002685546875,100.38076782226562
2,TO,binary,100,10000,35.26449966430664,35.19249725341797,0.07200241088867188,100.20459747314453
3,TO,binary,100,10000,35.32050323486328,35.19249725341797,0.1280059814453125,100.36373138427734
4,TO,binary,100,10000,35.30950164794922,35.19249725341797,0.11700439453125,100.33247375488281
5,TO,binary,100,10000,35.26249694824219,35.19249725341797,0.06999969482421875,100.19889831542969
6,TO,binary,100,10000,35.48699951171875,35.19249725341797,0.29450225830078125,100.83683776855469
0,FROM,binary,100,100000,153.9669952392578,153.9669952392578,0.0,100.0
1,FROM,binary,100,100000,165.63900756835938,153.9669952392578,11.672012329101562,107.58085632324219
2,FROM,binary,100,100000,154.34500122070312,153.9669952392578,0.3780059814453125,100.24551391601562
3,FROM,binary,100,100000,154.33599853515625,153.9669952392578,0.3690032958984375,100.23965454101562
4,FROM,binary,100,100000,154.1199951171875,153.9669952392578,0.1529998779296875,100.09937286376953
5,FROM,binary,100,100000,154.12399291992188,153.9669952392578,0.1569976806640625,100.10197448730469
6,FROM,binary,100,100000,158.86500549316406,153.9669952392578,4.89801025390625,103.18120574951172
0,TO,binary,100,100000,233.91200256347656,233.91200256347656,0.0,100.0
1,TO,binary,100,100000,233.7729949951172,233.91200256347656,-0.139007568359375,99.9405746459961
2,TO,binary,100,100000,233.50399780273438,233.91200256347656,-0.4080047607421875,99.82557678222656
3,TO,binary,100,100000,233.56900024414062,233.91200256347656,-0.3430023193359375,99.85336303710938
4,TO,binary,100,100000,233.68899536132812,233.91200256347656,-0.2230072021484375,99.9046630859375
5,TO,binary,100,100000,234.61599731445312,233.91200256347656,0.7039947509765625,100.30096435546875
6,TO,binary,100,100000,236.23899841308594,233.91200256347656,2.326995849609375,100.99481201171875
0,FROM,binary,100,1000000,1393.0899658203125,1393.0899658203125,0.0,100.0
1,FROM,binary,100,1000000,1508.0350341796875,1393.0899658203125,114.945068359375,108.25108337402344
2,FROM,binary,100,1000000,1394.25,1393.0899658203125,1.1600341796875,100.08326721191406
3,FROM,binary,100,1000000,1395.2099609375,1393.0899658203125,2.1199951171875,100.15218353271484
4,FROM,binary,100,1000000,1394.6240234375,1393.0899658203125,1.5340576171875,100.11011505126953
5,FROM,binary,100,1000000,1395.0860595703125,1393.0899658203125,1.99609375,100.1432876586914
6,FROM,binary,100,1000000,1395.1619873046875,1393.0899658203125,2.072021484375,100.14873504638672
0,TO,binary,100,1000000,2199.782958984375,2199.782958984375,0.0,100.0
1,TO,binary,100,1000000,2195.175048828125,2199.782958984375,-4.60791015625,99.79053497314453
2,TO,binary,100,1000000,2194.85400390625,2199.782958984375,-4.928955078125,99.77593231201172
3,TO,binary,100,1000000,2192.89111328125,2199.782958984375,-6.891845703125,99.68670654296875
4,TO,binary,100,1000000,2194.35009765625,2199.782958984375,-5.432861328125,99.7530288696289
5,TO,binary,100,1000000,2204.4189453125,2199.782958984375,4.635986328125,100.21074676513672
6,TO,binary,100,1000000,2202.29296875,2199.782958984375,2.510009765625,100.11410522460938
0,FROM,csv,1,10,13.08899974822998,13.08899974822998,0.0,100.0
1,FROM,csv,1,10,13.232999801635742,13.08899974822998,0.14400005340576172,101.10015869140625
2,FROM,csv,1,10,13.23799991607666,13.08899974822998,0.1490001678466797,101.13836669921875
3,FROM,csv,1,10,13.22599983215332,13.08899974822998,0.13700008392333984,101.04668426513672
4,FROM,csv,1,10,13.331000328063965,13.08899974822998,0.24200057983398438,101.84889221191406
5,FROM,csv,1,10,13.239999771118164,13.08899974822998,0.1510000228881836,101.15363311767578
6,FROM,csv,1,10,13.26200008392334,13.08899974822998,0.17300033569335938,101.32172393798828
0,TO,csv,1,10,12.895999908447266,12.895999908447266,0.0,100.0
1,TO,csv,1,10,12.972999572753906,12.895999908447266,0.07699966430664062,100.59708404541016
2,TO,csv,1,10,12.996999740600586,12.895999908447266,0.10099983215332031,100.78319549560547
3,TO,csv,1,10,12.991000175476074,12.895999908447266,0.0950002670288086,100.73666381835938
4,TO,csv,1,10,12.982999801635742,12.895999908447266,0.08699989318847656,100.67462921142578
5,TO,csv,1,10,12.923999786376953,12.895999908447266,0.0279998779296875,100.21711730957031
6,TO,csv,1,10,12.984000205993652,12.895999908447266,0.08800029754638672,100.68238830566406
0,FROM,csv,1,100,13.17300033569336,13.17300033569336,0.0,100.0
1,FROM,csv,1,100,13.333000183105469,13.17300033569336,0.15999984741210938,101.214599609375
2,FROM,csv,1,100,13.375,13.17300033569336,0.20199966430664062,101.53343963623047
3,FROM,csv,1,100,13.442000389099121,13.17300033569336,0.2690000534057617,102.04205322265625
4,FROM,csv,1,100,13.413999557495117,13.17300033569336,0.2409992218017578,101.8294906616211
5,FROM,csv,1,100,13.4350004196167,13.17300033569336,0.26200008392333984,101.9889144897461
6,FROM,csv,1,100,13.284000396728516,13.17300033569336,0.11100006103515625,100.8426284790039
0,TO,csv,1,100,12.77299976348877,12.77299976348877,0.0,100.0
1,TO,csv,1,100,12.946000099182129,12.77299976348877,0.17300033569335938,101.35442352294922
2,TO,csv,1,100,12.9350004196167,12.77299976348877,0.1620006561279297,101.26830291748047
3,TO,csv,1,100,13.038000106811523,12.77299976348877,0.2650003433227539,102.07469177246094
4,TO,csv,1,100,13.076000213623047,12.77299976348877,0.30300045013427734,102.3721923828125
5,TO,csv,1,100,12.949000358581543,12.77299976348877,0.17600059509277344,101.37791442871094
6,TO,csv,1,100,13.024999618530273,12.77299976348877,0.2519998550415039,101.97291564941406
0,FROM,csv,1,1000,15.23799991607666,15.23799991607666,0.0,100.0
1,FROM,csv,1,1000,15.449999809265137,15.23799991607666,0.21199989318847656,101.3912582397461
2,FROM,csv,1,1000,15.373000144958496,15.23799991607666,0.13500022888183594,100.88594055175781
3,FROM,csv,1,1000,15.406999588012695,15.23799991607666,0.16899967193603516,101.10906219482422
4,FROM,csv,1,1000,15.45300006866455,15.23799991607666,0.21500015258789062,101.41094970703125
5,FROM,csv,1,1000,15.559000015258789,15.23799991607666,0.3210000991821289,102.1065673828125
6,FROM,csv,1,1000,15.477999687194824,15.23799991607666,0.23999977111816406,101.57500457763672
0,TO,csv,1,1000,12.918000221252441,12.918000221252441,0.0,100.0
1,TO,csv,1,1000,13.038000106811523,12.918000221252441,0.11999988555908203,100.92893981933594
2,TO,csv,1,1000,12.939000129699707,12.918000221252441,0.020999908447265625,100.16256713867188
3,TO,csv,1,1000,13.104000091552734,12.918000221252441,0.18599987030029297,101.4398422241211
4,TO,csv,1,1000,13.095999717712402,12.918000221252441,0.17799949645996094,101.37791442871094
5,TO,csv,1,1000,12.932999610900879,12.918000221252441,0.0149993896484375,100.1161117553711
6,TO,csv,1,1000,13.02400016784668,12.918000221252441,0.10599994659423828,100.82056427001953
0,FROM,csv,1,10000,15.803999900817871,15.803999900817871,0.0,100.0
1,FROM,csv,1,10000,15.936500549316406,15.803999900817871,0.13250064849853516,100.8384017944336
2,FROM,csv,1,10000,15.916999816894531,15.803999900817871,0.11299991607666016,100.71500396728516
3,FROM,csv,1,10000,16.057498931884766,15.803999900817871,0.25349903106689453,101.60401916503906
4,FROM,csv,1,10000,16.017499923706055,15.803999900817871,0.2135000228881836,101.3509292602539
5,FROM,csv,1,10000,16.109500885009766,15.803999900817871,0.30550098419189453,101.93305969238281
6,FROM,csv,1,10000,15.93899917602539,15.803999900817871,0.13499927520751953,100.85420227050781
0,TO,csv,1,10000,13.68600082397461,13.68600082397461,0.0,100.0
1,TO,csv,1,10000,13.774999618530273,13.68600082397461,0.08899879455566406,100.65028381347656
2,TO,csv,1,10000,13.79800033569336,13.68600082397461,0.11199951171875,100.81834411621094
3,TO,csv,1,10000,13.878999710083008,13.68600082397461,0.19299888610839844,101.41018676757812
4,TO,csv,1,10000,13.909500122070312,13.68600082397461,0.22349929809570312,101.63304901123047
5,TO,csv,1,10000,14.002500534057617,13.68600082397461,0.3164997100830078,102.31257629394531
6,TO,csv,1,10000,13.892000198364258,13.68600082397461,0.20599937438964844,101.50518798828125
0,FROM,csv,1,100000,21.47800064086914,21.47800064086914,0.0,100.0
1,FROM,csv,1,100000,21.562000274658203,21.47800064086914,0.0839996337890625,100.39109802246094
2,FROM,csv,1,100000,22.716999053955078,21.47800064086914,1.2389984130859375,105.7686767578125
3,FROM,csv,1,100000,22.00200080871582,21.47800064086914,0.5240001678466797,102.43970489501953
4,FROM,csv,1,100000,21.66699981689453,21.47800064086914,0.18899917602539062,100.87996673583984
5,FROM,csv,1,100000,21.510000228881836,21.47800064086914,0.03199958801269531,100.14898681640625
6,FROM,csv,1,100000,21.488000869750977,21.47800064086914,0.010000228881835938,100.04656219482422
0,TO,csv,1,100000,21.742000579833984,21.742000579833984,0.0,100.0
1,TO,csv,1,100000,21.79199981689453,21.742000579833984,0.049999237060546875,100.22996520996094
2,TO,csv,1,100000,21.777999877929688,21.742000579833984,0.035999298095703125,100.16557312011719
3,TO,csv,1,100000,21.950000762939453,21.742000579833984,0.20800018310546875,100.95668029785156
4,TO,csv,1,100000,21.945999145507812,21.742000579833984,0.20399856567382812,100.93827056884766
5,TO,csv,1,100000,21.777000427246094,21.742000579833984,0.034999847412109375,100.16098022460938
6,TO,csv,1,100000,21.597000122070312,21.742000579833984,-0.14500045776367188,99.33308410644531
0,FROM,csv,1,1000000,77.3280029296875,77.3280029296875,0.0,100.0
1,FROM,csv,1,1000000,77.15499877929688,77.3280029296875,-0.173004150390625,99.77627563476562
2,FROM,csv,1,1000000,78.70600128173828,77.3280029296875,1.3779983520507812,101.78201293945312
3,FROM,csv,1,1000000,80.84200286865234,77.3280029296875,3.5139999389648438,104.54428100585938
4,FROM,csv,1,1000000,78.09200286865234,77.3280029296875,0.7639999389648438,100.98799133300781
5,FROM,csv,1,1000000,77.625,77.3280029296875,0.2969970703125,100.38407135009766
6,FROM,csv,1,1000000,77.8280029296875,77.3280029296875,0.5,100.64659118652344
0,TO,csv,1,1000000,97.7760009765625,97.7760009765625,0.0,100.0
1,TO,csv,1,1000000,98.20800018310547,97.7760009765625,0.43199920654296875,100.44182586669922
2,TO,csv,1,1000000,98.16500091552734,97.7760009765625,0.38899993896484375,100.3978500366211
3,TO,csv,1,1000000,98.01300048828125,97.7760009765625,0.23699951171875,100.24238586425781
4,TO,csv,1,1000000,99.12200164794922,97.7760009765625,1.3460006713867188,101.37661743164062
5,TO,csv,1,1000000,97.95500183105469,97.7760009765625,0.1790008544921875,100.18306732177734
6,TO,csv,1,1000000,97.88899993896484,97.7760009765625,0.11299896240234375,100.11557006835938
0,FROM,csv,10,10,13.779000282287598,13.779000282287598,0.0,100.0
1,FROM,csv,10,10,13.170999526977539,13.779000282287598,-0.6080007553100586,95.58747863769531
2,FROM,csv,10,10,13.277000427246094,13.779000282287598,-0.5019998550415039,96.35677337646484
3,FROM,csv,10,10,13.329000473022461,13.779000282287598,-0.4499998092651367,96.73416137695312
4,FROM,csv,10,10,13.300999641418457,13.779000282287598,-0.4780006408691406,96.53095245361328
5,FROM,csv,10,10,13.36400032043457,13.779000282287598,-0.41499996185302734,96.98817443847656
6,FROM,csv,10,10,13.204000473022461,13.779000282287598,-0.5749998092651367,95.82698059082031
0,TO,csv,10,10,13.564000129699707,13.564000129699707,0.0,100.0
1,TO,csv,10,10,12.904000282287598,13.564000129699707,-0.6599998474121094,95.1341781616211
2,TO,csv,10,10,12.916000366210938,13.564000129699707,-0.6479997634887695,95.22264862060547
3,TO,csv,10,10,12.977999687194824,13.564000129699707,-0.5860004425048828,95.67973327636719
4,TO,csv,10,10,13.029000282287598,13.564000129699707,-0.5349998474121094,96.05573272705078
5,TO,csv,10,10,12.972000122070312,13.564000129699707,-0.5920000076293945,95.63550567626953
6,TO,csv,10,10,12.944000244140625,13.564000129699707,-0.619999885559082,95.4290771484375
0,FROM,csv,10,100,14.0,14.0,0.0,100.0
1,FROM,csv,10,100,13.289999961853027,14.0,-0.7100000381469727,94.9285659790039
2,FROM,csv,10,100,13.407999992370605,14.0,-0.5920000076293945,95.77142333984375
3,FROM,csv,10,100,13.440999984741211,14.0,-0.5590000152587891,96.00714111328125
4,FROM,csv,10,100,13.375,14.0,-0.625,95.53571319580078
5,FROM,csv,10,100,13.41100025177002,14.0,-0.5889997482299805,95.79286193847656
6,FROM,csv,10,100,13.493000030517578,14.0,-0.5069999694824219,96.37857055664062
0,TO,csv,10,100,13.706000328063965,13.706000328063965,0.0,100.0
1,TO,csv,10,100,12.968000411987305,13.706000328063965,-0.7379999160766602,94.61549377441406
2,TO,csv,10,100,13.00100040435791,13.706000328063965,-0.7049999237060547,94.85626983642578
3,TO,csv,10,100,13.116000175476074,13.706000328063965,-0.5900001525878906,95.69532012939453
4,TO,csv,10,100,13.020000457763672,13.706000328063965,-0.685999870300293,94.9948959350586
5,TO,csv,10,100,13.008999824523926,13.706000328063965,-0.6970005035400391,94.91463470458984
6,TO,csv,10,100,13.0600004196167,13.706000328063965,-0.6459999084472656,95.28673553466797
0,FROM,csv,10,1000,16.326000213623047,16.326000213623047,0.0,100.0
1,FROM,csv,10,1000,15.536999702453613,16.326000213623047,-0.7890005111694336,95.1672134399414
2,FROM,csv,10,1000,15.53499984741211,16.326000213623047,-0.7910003662109375,95.15496826171875
3,FROM,csv,10,1000,15.756999969482422,16.326000213623047,-0.569000244140625,96.51476287841797
4,FROM,csv,10,1000,15.63700008392334,16.326000213623047,-0.689000129699707,95.77973175048828
5,FROM,csv,10,1000,15.557000160217285,16.326000213623047,-0.7690000534057617,95.28971862792969
6,FROM,csv,10,1000,15.677000045776367,16.326000213623047,-0.6490001678466797,96.02474212646484
0,TO,csv,10,1000,13.727999687194824,13.727999687194824,0.0,100.0
1,TO,csv,10,1000,13.0649995803833,13.727999687194824,-0.6630001068115234,95.17045593261719
2,TO,csv,10,1000,13.25,13.727999687194824,-0.4779996871948242,96.51806640625
3,TO,csv,10,1000,13.213000297546387,13.727999687194824,-0.5149993896484375,96.24855041503906
4,TO,csv,10,1000,13.196999549865723,13.727999687194824,-0.5310001373291016,96.13198852539062
5,TO,csv,10,1000,13.182999610900879,13.727999687194824,-0.5450000762939453,96.0300064086914
6,TO,csv,10,1000,13.128000259399414,13.727999687194824,-0.5999994277954102,95.62937927246094
0,FROM,csv,10,10000,18.194000244140625,18.194000244140625,0.0,100.0
1,FROM,csv,10,10000,17.51099967956543,18.194000244140625,-0.6830005645751953,96.24600982666016
2,FROM,csv,10,10000,17.5989990234375,18.194000244140625,-0.595001220703125,96.72968292236328
3,FROM,csv,10,10000,17.719499588012695,18.194000244140625,-0.4745006561279297,97.3919906616211
4,FROM,csv,10,10000,17.729000091552734,18.194000244140625,-0.4650001525878906,97.4442138671875
5,FROM,csv,10,10000,17.645999908447266,18.194000244140625,-0.5480003356933594,96.9880142211914
6,FROM,csv,10,10000,17.614999771118164,18.194000244140625,-0.5790004730224609,96.817626953125
0,TO,csv,10,10000,16.168498992919922,16.168498992919922,0.0,100.0
1,TO,csv,10,10000,15.409000396728516,16.168498992919922,-0.7594985961914062,95.30260467529297
2,TO,csv,10,10000,15.371000289916992,16.168498992919922,-0.7974987030029297,95.06758117675781
3,TO,csv,10,10000,15.460500717163086,16.168498992919922,-0.7079982757568359,95.62112426757812
4,TO,csv,10,10000,15.47249984741211,16.168498992919922,-0.6959991455078125,95.69534301757812
5,TO,csv,10,10000,15.480999946594238,16.168498992919922,-0.6874990463256836,95.74790954589844
6,TO,csv,10,10000,15.417499542236328,16.168498992919922,-0.7509994506835938,95.35517120361328
0,FROM,csv,10,100000,38.61600112915039,38.61600112915039,0.0,100.0
1,FROM,csv,10,100000,37.742000579833984,38.61600112915039,-0.8740005493164062,97.73668670654297
2,FROM,csv,10,100000,37.90399932861328,38.61600112915039,-0.7120018005371094,98.15620422363281
3,FROM,csv,10,100000,38.099998474121094,38.61600112915039,-0.5160026550292969,98.66375732421875
4,FROM,csv,10,100000,38.000999450683594,38.61600112915039,-0.6150016784667969,98.40739440917969
5,FROM,csv,10,100000,37.76900100708008,38.61600112915039,-0.8470001220703125,97.80661010742188
6,FROM,csv,10,100000,37.84299850463867,38.61600112915039,-0.7730026245117188,97.99822998046875
0,TO,csv,10,100000,38.40800094604492,38.40800094604492,0.0,100.0
1,TO,csv,10,100000,37.47600173950195,38.40800094604492,-0.9319992065429688,97.57342529296875
2,TO,csv,10,100000,37.38800048828125,38.40800094604492,-1.0200004577636719,97.34429931640625
3,TO,csv,10,100000,37.5099983215332,38.40800094604492,-0.8980026245117188,97.66193389892578
4,TO,csv,10,100000,37.4640007019043,38.40800094604492,-0.944000244140625,97.54217529296875
5,TO,csv,10,100000,37.76300048828125,38.40800094604492,-0.6450004577636719,98.32066345214844
6,TO,csv,10,100000,37.57400131225586,38.40800094604492,-0.8339996337890625,97.82858276367188
0,FROM,csv,10,1000000,239.69900512695312,239.69900512695312,0.0,100.0
1,FROM,csv,10,1000000,237.1230010986328,239.69900512695312,-2.5760040283203125,98.9253158569336
2,FROM,csv,10,1000000,239.08299255371094,239.69900512695312,-0.6160125732421875,99.74301147460938
3,FROM,csv,10,1000000,239.75399780273438,239.69900512695312,0.05499267578125,100.02294921875
4,FROM,csv,10,1000000,238.9669952392578,239.69900512695312,-0.7320098876953125,99.69461822509766
5,FROM,csv,10,1000000,239.36199951171875,239.69900512695312,-0.337005615234375,99.85940551757812
6,FROM,csv,10,1000000,238.70199584960938,239.69900512695312,-0.99700927734375,99.58405303955078
0,TO,csv,10,1000000,258.94500732421875,258.94500732421875,0.0,100.0
1,TO,csv,10,1000000,253.99600219726562,258.94500732421875,-4.949005126953125,98.08878326416016
2,TO,csv,10,1000000,253.2169952392578,258.94500732421875,-5.7280120849609375,97.7879409790039
3,TO,csv,10,1000000,253.56500244140625,258.94500732421875,-5.3800048828125,97.9223403930664
4,TO,csv,10,1000000,254.58999633789062,258.94500732421875,-4.355010986328125,98.31816864013672
5,TO,csv,10,1000000,255.4720001220703,258.94500732421875,-3.4730072021484375,98.6587905883789
6,TO,csv,10,1000000,255.0679931640625,258.94500732421875,-3.87701416015625,98.50276947021484
0,FROM,csv,100,10,13.199000358581543,13.199000358581543,0.0,100.0
1,FROM,csv,100,10,13.282999992370605,13.199000358581543,0.0839996337890625,100.63641357421875
2,FROM,csv,100,10,13.251999855041504,13.199000358581543,0.05299949645996094,100.40154266357422
3,FROM,csv,100,10,13.437000274658203,13.199000358581543,0.23799991607666016,101.80316925048828
4,FROM,csv,100,10,13.409000396728516,13.199000358581543,0.21000003814697266,101.59102630615234
5,FROM,csv,100,10,13.300000190734863,13.199000358581543,0.10099983215332031,100.76520538330078
6,FROM,csv,100,10,13.23799991607666,13.199000358581543,0.03899955749511719,100.29547119140625
0,TO,csv,100,10,13.375,13.375,0.0,100.0
1,TO,csv,100,10,12.892999649047852,13.375,-0.48200035095214844,96.3962631225586
2,TO,csv,100,10,13.026000022888184,13.375,-0.3489999771118164,97.39065551757812
3,TO,csv,100,10,13.010000228881836,13.375,-0.36499977111816406,97.27103424072266
4,TO,csv,100,10,13.13599967956543,13.375,-0.2390003204345703,98.21308135986328
5,TO,csv,100,10,13.0649995803833,13.375,-0.3100004196166992,97.68223571777344
6,TO,csv,100,10,13.00100040435791,13.375,-0.37399959564208984,97.20374298095703
0,FROM,csv,100,100,13.96500015258789,13.96500015258789,0.0,100.0
1,FROM,csv,100,100,13.645999908447266,13.96500015258789,-0.319000244140625,97.7157211303711
2,FROM,csv,100,100,13.704000473022461,13.96500015258789,-0.2609996795654297,98.13104248046875
3,FROM,csv,100,100,13.666000366210938,13.96500015258789,-0.2989997863769531,97.85893249511719
4,FROM,csv,100,100,13.736000061035156,13.96500015258789,-0.22900009155273438,98.36018371582031
5,FROM,csv,100,100,13.630000114440918,13.96500015258789,-0.33500003814697266,97.60114288330078
6,FROM,csv,100,100,13.663000106811523,13.96500015258789,-0.3020000457763672,97.83744812011719
0,TO,csv,100,100,13.272000312805176,13.272000312805176,0.0,100.0
1,TO,csv,100,100,13.008999824523926,13.272000312805176,-0.26300048828125,98.01837921142578
2,TO,csv,100,100,13.189000129699707,13.272000312805176,-0.08300018310546875,99.37461853027344
3,TO,csv,100,100,13.178999900817871,13.272000312805176,-0.09300041198730469,99.29927825927734
4,TO,csv,100,100,13.180999755859375,13.272000312805176,-0.09100055694580078,99.31434631347656
5,TO,csv,100,100,13.098999977111816,13.272000312805176,-0.17300033569335938,98.69650268554688
6,TO,csv,100,100,13.194000244140625,13.272000312805176,-0.07800006866455078,99.41230010986328
0,FROM,csv,100,1000,15.444999694824219,15.444999694824219,0.0,100.0
1,FROM,csv,100,1000,15.87399959564209,15.444999694824219,0.4289999008178711,102.77760314941406
2,FROM,csv,100,1000,15.727999687194824,15.444999694824219,0.28299999237060547,101.83230590820312
3,FROM,csv,100,1000,15.854999542236328,15.444999694824219,0.4099998474121094,102.65457916259766
4,FROM,csv,100,1000,15.946000099182129,15.444999694824219,0.5010004043579102,103.24376678466797
5,FROM,csv,100,1000,15.772000312805176,15.444999694824219,0.32700061798095703,102.11719512939453
6,FROM,csv,100,1000,15.906999588012695,15.444999694824219,0.46199989318847656,102.99125671386719
0,TO,csv,100,1000,15.064000129699707,15.064000129699707,0.0,100.0
1,TO,csv,100,1000,14.76099967956543,15.064000129699707,-0.30300045013427734,97.98857879638672
2,TO,csv,100,1000,14.715999603271484,15.064000129699707,-0.34800052642822266,97.68985748291016
3,TO,csv,100,1000,14.795000076293945,15.064000129699707,-0.2690000534057617,98.21428680419922
4,TO,csv,100,1000,14.776000022888184,15.064000129699707,-0.28800010681152344,98.0881576538086
5,TO,csv,100,1000,14.833999633789062,15.064000129699707,-0.23000049591064453,98.47318267822266
6,TO,csv,100,1000,14.79800033569336,15.064000129699707,-0.26599979400634766,98.23419952392578
0,FROM,csv,100,10000,34.33650207519531,34.33650207519531,0.0,100.0
1,FROM,csv,100,10000,33.579498291015625,34.33650207519531,-0.7570037841796875,97.79533386230469
2,FROM,csv,100,10000,33.70649719238281,34.33650207519531,-0.6300048828125,98.16519927978516
3,FROM,csv,100,10000,33.746498107910156,34.33650207519531,-0.5900039672851562,98.28170013427734
4,FROM,csv,100,10000,33.74500274658203,34.33650207519531,-0.5914993286132812,98.27735137939453
5,FROM,csv,100,10000,33.759498596191406,34.33650207519531,-0.5770034790039062,98.3195571899414
6,FROM,csv,100,10000,33.68499755859375,34.33650207519531,-0.6515045166015625,98.10258483886719
0,TO,csv,100,10000,31.31399917602539,31.31399917602539,0.0,100.0
1,TO,csv,100,10000,30.394500732421875,31.31399917602539,-0.9194984436035156,97.0636215209961
2,TO,csv,100,10000,30.513999938964844,31.31399917602539,-0.7999992370605469,97.44522857666016
3,TO,csv,100,10000,30.61349868774414,31.31399917602539,-0.70050048828125,97.76297760009766
4,TO,csv,100,10000,30.61050033569336,31.31399917602539,-0.7034988403320312,97.75340270996094
5,TO,csv,100,10000,30.82900047302246,31.31399917602539,-0.4849987030029297,98.451171875
6,TO,csv,100,10000,30.769001007080078,31.31399917602539,-0.5449981689453125,98.25956726074219
0,FROM,csv,100,100000,209.6750030517578,209.6750030517578,0.0,100.0
1,FROM,csv,100,100000,210.47300720214844,209.6750030517578,0.798004150390625,100.38058471679688
2,FROM,csv,100,100000,210.28599548339844,209.6750030517578,0.610992431640625,100.29139709472656
3,FROM,csv,100,100000,211.6999969482422,209.6750030517578,2.024993896484375,100.96577453613281
4,FROM,csv,100,100000,211.11599731445312,209.6750030517578,1.4409942626953125,100.687255859375
5,FROM,csv,100,100000,212.4010009765625,209.6750030517578,2.7259979248046875,101.30010986328125
6,FROM,csv,100,100000,210.48300170898438,209.6750030517578,0.8079986572265625,100.3853530883789
0,TO,csv,100,100000,191.47500610351562,191.47500610351562,0.0,100.0
1,TO,csv,100,100000,186.43600463867188,191.47500610351562,-5.03900146484375,97.36832427978516
2,TO,csv,100,100000,186.4199981689453,191.47500610351562,-5.0550079345703125,97.35997009277344
3,TO,csv,100,100000,186.31100463867188,191.47500610351562,-5.16400146484375,97.30303955078125
4,TO,csv,100,100000,186.50999450683594,191.47500610351562,-4.9650115966796875,97.40696716308594
5,TO,csv,100,100000,189.39599609375,191.47500610351562,-2.079010009765625,98.91421508789062
6,TO,csv,100,100000,189.23699951171875,191.47500610351562,-2.238006591796875,98.8311767578125
0,FROM,csv,100,1000000,1977.1629638671875,1977.1629638671875,0.0,100.0
1,FROM,csv,100,1000000,1974.6800537109375,1977.1629638671875,-2.48291015625,99.87442016601562
2,FROM,csv,100,1000000,1989.511962890625,1977.1629638671875,12.3489990234375,100.62458801269531
3,FROM,csv,100,1000000,1988.572998046875,1977.1629638671875,11.4100341796875,100.57709503173828
4,FROM,csv,100,1000000,1987.0360107421875,1977.1629638671875,9.873046875,100.49935913085938
5,FROM,csv,100,1000000,1997.5360107421875,1977.1629638671875,20.373046875,101.0304183959961
6,FROM,csv,100,1000000,1985.551025390625,1977.1629638671875,8.3880615234375,100.42424011230469
0,TO,csv,100,1000000,1757.5579833984375,1757.5579833984375,0.0,100.0
1,TO,csv,100,1000000,1728.4649658203125,1757.5579833984375,-29.093017578125,98.34468841552734
2,TO,csv,100,1000000,1727.134033203125,1757.5579833984375,-30.4239501953125,98.26895904541016
3,TO,csv,100,1000000,1727.2010498046875,1757.5579833984375,-30.35693359375,98.27277374267578
4,TO,csv,100,1000000,1728.487060546875,1757.5579833984375,-29.0709228515625,98.345947265625
5,TO,csv,100,1000000,1757.0699462890625,1757.5579833984375,-0.488037109375,99.97222900390625
6,TO,csv,100,1000000,1764.3609619140625,1757.5579833984375,6.802978515625,100.38706970214844
0,FROM,text,1,10,13.157999992370605,13.157999992370605,0.0,100.0
1,FROM,text,1,10,14.152000427246094,13.157999992370605,0.9940004348754883,107.55433654785156
2,FROM,text,1,10,14.218999862670898,13.157999992370605,1.060999870300293,108.06352996826172
3,FROM,text,1,10,14.029999732971191,13.157999992370605,0.8719997406005859,106.62714385986328
4,FROM,text,1,10,13.324999809265137,13.157999992370605,0.16699981689453125,101.2691879272461
5,FROM,text,1,10,14.366000175476074,13.157999992370605,1.2080001831054688,109.18072509765625
6,FROM,text,1,10,13.746999740600586,13.157999992370605,0.5889997482299805,104.47635650634766
0,TO,text,1,10,13.163999557495117,13.163999557495117,0.0,100.0
1,TO,text,1,10,13.866999626159668,13.163999557495117,0.7030000686645508,105.34032440185547
2,TO,text,1,10,13.87600040435791,13.163999557495117,0.712000846862793,105.40869140625
3,TO,text,1,10,14.515000343322754,13.163999557495117,1.3510007858276367,110.26284790039062
4,TO,text,1,10,13.27299976348877,13.163999557495117,0.10900020599365234,100.82801818847656
5,TO,text,1,10,14.012999534606934,13.163999557495117,0.8489999771118164,106.44941711425781
6,TO,text,1,10,13.82800006866455,13.163999557495117,0.6640005111694336,105.0440673828125
0,FROM,text,1,100,13.234999656677246,13.234999656677246,0.0,100.0
1,FROM,text,1,100,14.295000076293945,13.234999656677246,1.0600004196166992,108.00907897949219
2,FROM,text,1,100,13.86299991607666,13.234999656677246,0.6280002593994141,104.7449951171875
3,FROM,text,1,100,13.027999877929688,13.234999656677246,-0.2069997787475586,98.43596649169922
4,FROM,text,1,100,13.982999801635742,13.234999656677246,0.7480001449584961,105.65167999267578
5,FROM,text,1,100,14.527999877929688,13.234999656677246,1.2930002212524414,109.76954650878906
6,FROM,text,1,100,13.86299991607666,13.234999656677246,0.6280002593994141,104.7449951171875
0,TO,text,1,100,12.892999649047852,12.892999649047852,0.0,100.0
1,TO,text,1,100,13.76099967956543,12.892999649047852,0.8680000305175781,106.73233032226562
2,TO,text,1,100,13.732999801635742,12.892999649047852,0.8400001525878906,106.51516723632812
3,TO,text,1,100,13.331999778747559,12.892999649047852,0.43900012969970703,103.40495300292969
4,TO,text,1,100,13.229999542236328,12.892999649047852,0.33699989318847656,102.61381530761719
5,TO,text,1,100,14.064000129699707,12.892999649047852,1.1710004806518555,109.08245086669922
6,TO,text,1,100,13.14799976348877,12.892999649047852,0.25500011444091797,101.97781372070312
0,FROM,text,1,1000,15.375,15.375,0.0,100.0
1,FROM,text,1,1000,15.96500015258789,15.375,0.5900001525878906,103.83739471435547
2,FROM,text,1,1000,15.26099967956543,15.375,-0.11400032043457031,99.25853729248047
3,FROM,text,1,1000,15.859000205993652,15.375,0.48400020599365234,103.1479721069336
4,FROM,text,1,1000,16.2810001373291,15.375,0.9060001373291016,105.89268493652344
5,FROM,text,1,1000,16.118000030517578,15.375,0.7430000305175781,104.83251953125
6,FROM,text,1,1000,15.536999702453613,15.375,0.16199970245361328,101.05365753173828
0,TO,text,1,1000,12.979999542236328,12.979999542236328,0.0,100.0
1,TO,text,1,1000,13.725000381469727,12.979999542236328,0.7450008392333984,105.73960876464844
2,TO,text,1,1000,12.920999526977539,12.979999542236328,-0.05900001525878906,99.54545593261719
3,TO,text,1,1000,12.972999572753906,12.979999542236328,-0.006999969482421875,99.9460678100586
4,TO,text,1,1000,13.812999725341797,12.979999542236328,0.8330001831054688,106.41757202148438
5,TO,text,1,1000,13.885000228881836,12.979999542236328,0.9050006866455078,106.9722671508789
6,TO,text,1,1000,13.531000137329102,12.979999542236328,0.5510005950927734,104.2449951171875
0,FROM,text,1,10000,15.756000518798828,15.756000518798828,0.0,100.0
1,FROM,text,1,10000,15.86299991607666,15.756000518798828,0.10699939727783203,100.6791000366211
2,FROM,text,1,10000,16.576000213623047,15.756000518798828,0.8199996948242188,105.2043685913086
3,FROM,text,1,10000,16.612998962402344,15.756000518798828,0.8569984436035156,105.4391860961914
4,FROM,text,1,10000,16.938499450683594,15.756000518798828,1.1824989318847656,107.50507354736328
5,FROM,text,1,10000,15.58650016784668,15.756000518798828,-0.16950035095214844,98.9242172241211
6,FROM,text,1,10000,16.770000457763672,15.756000518798828,1.0139999389648438,106.4356460571289
0,TO,text,1,10000,13.617000579833984,13.617000579833984,0.0,100.0
1,TO,text,1,10000,13.686500549316406,13.617000579833984,0.06949996948242188,100.51039123535156
2,TO,text,1,10000,14.291999816894531,13.617000579833984,0.6749992370605469,104.95703125
3,TO,text,1,10000,14.000999450683594,13.617000579833984,0.3839988708496094,102.81999206542969
4,TO,text,1,10000,14.652999877929688,13.617000579833984,1.0359992980957031,107.60812377929688
5,TO,text,1,10000,13.673500061035156,13.617000579833984,0.056499481201171875,100.4149169921875
6,TO,text,1,10000,14.473499298095703,13.617000579833984,0.8564987182617188,106.28992462158203
0,FROM,text,1,100000,21.266000747680664,21.266000747680664,0.0,100.0
1,FROM,text,1,100000,22.07699966430664,21.266000747680664,0.8109989166259766,103.81359100341797
2,FROM,text,1,100000,22.391000747680664,21.266000747680664,1.125,105.2901382446289
3,FROM,text,1,100000,22.7189998626709,21.266000747680664,1.4529991149902344,106.83248901367188
4,FROM,text,1,100000,22.264999389648438,21.266000747680664,0.9989986419677734,104.6976318359375
5,FROM,text,1,100000,22.11400032043457,21.266000747680664,0.8479995727539062,103.98758697509766
6,FROM,text,1,100000,22.427000045776367,21.266000747680664,1.1609992980957031,105.45941925048828
0,TO,text,1,100000,20.93899917602539,20.93899917602539,0.0,100.0
1,TO,text,1,100000,21.784000396728516,20.93899917602539,0.845001220703125,104.03553009033203
2,TO,text,1,100000,21.774999618530273,20.93899917602539,0.8360004425048828,103.9925537109375
3,TO,text,1,100000,22.094999313354492,20.93899917602539,1.1560001373291016,105.52079772949219
4,TO,text,1,100000,22.299999237060547,20.93899917602539,1.3610000610351562,106.49983978271484
5,TO,text,1,100000,21.075000762939453,20.93899917602539,0.1360015869140625,100.6495132446289
6,TO,text,1,100000,22.02899932861328,20.93899917602539,1.0900001525878906,105.20559692382812
0,FROM,text,1,1000000,75.63500213623047,75.63500213623047,0.0,100.0
1,FROM,text,1,1000000,77.66100311279297,75.63500213623047,2.0260009765625,102.67865753173828
2,FROM,text,1,1000000,78.61399841308594,75.63500213623047,2.9789962768554688,103.93865203857422
3,FROM,text,1,1000000,79.91500091552734,75.63500213623047,4.279998779296875,105.65876007080078
4,FROM,text,1,1000000,75.60700225830078,75.63500213623047,-0.0279998779296875,99.96298217773438
5,FROM,text,1,1000000,78.80000305175781,75.63500213623047,3.1650009155273438,104.1845703125
6,FROM,text,1,1000000,78.7229995727539,75.63500213623047,3.0879974365234375,104.082763671875
0,TO,text,1,1000000,91.69300079345703,91.69300079345703,0.0,100.0
1,TO,text,1,1000000,93.10800170898438,91.69300079345703,1.4150009155273438,101.5431900024414
2,TO,text,1,1000000,93.16400146484375,91.69300079345703,1.4710006713867188,101.6042709350586
3,TO,text,1,1000000,93.33200073242188,91.69300079345703,1.6389999389648438,101.78748321533203
4,TO,text,1,1000000,94.1240005493164,91.69300079345703,2.430999755859375,102.65123748779297
5,TO,text,1,1000000,93.05699920654297,91.69300079345703,1.3639984130859375,101.48756408691406
6,TO,text,1,1000000,92.66899871826172,91.69300079345703,0.9759979248046875,101.06442260742188
0,FROM,text,10,10,13.111000061035156,13.111000061035156,0.0,100.0
1,FROM,text,10,10,14.03600025177002,13.111000061035156,0.9250001907348633,107.0551528930664
2,FROM,text,10,10,14.149999618530273,13.111000061035156,1.0389995574951172,107.92463684082031
3,FROM,text,10,10,13.642000198364258,13.111000061035156,0.5310001373291016,104.05004119873047
4,FROM,text,10,10,12.925999641418457,13.111000061035156,-0.18500041961669922,98.5889663696289
5,FROM,text,10,10,14.322999954223633,13.111000061035156,1.2119998931884766,109.244140625
6,FROM,text,10,10,12.9350004196167,13.111000061035156,-0.17599964141845703,98.65762329101562
0,TO,text,10,10,12.857999801635742,12.857999801635742,0.0,100.0
1,TO,text,10,10,13.982000350952148,12.857999801635742,1.1240005493164062,108.74163818359375
2,TO,text,10,10,13.937000274658203,12.857999801635742,1.079000473022461,108.39166259765625
3,TO,text,10,10,14.031999588012695,12.857999801635742,1.1739997863769531,109.13050079345703
4,TO,text,10,10,12.61400032043457,12.857999801635742,-0.24399948120117188,98.10235595703125
5,TO,text,10,10,14.184000015258789,12.857999801635742,1.3260002136230469,110.31265258789062
6,TO,text,10,10,12.756999969482422,12.857999801635742,-0.10099983215332031,99.2145004272461
0,FROM,text,10,100,13.237000465393066,13.237000465393066,0.0,100.0
1,FROM,text,10,100,14.199000358581543,13.237000465393066,0.9619998931884766,107.26750946044922
2,FROM,text,10,100,13.11400032043457,13.237000465393066,-0.1230001449584961,99.07078552246094
3,FROM,text,10,100,13.055999755859375,13.237000465393066,-0.1810007095336914,98.63261413574219
4,FROM,text,10,100,13.46399974822998,13.237000465393066,0.22699928283691406,101.71488189697266
5,FROM,text,10,100,13.17300033569336,13.237000465393066,-0.06400012969970703,99.5165023803711
6,FROM,text,10,100,13.121000289916992,13.237000465393066,-0.11600017547607422,99.12367248535156
0,TO,text,10,100,12.890999794006348,12.890999794006348,0.0,100.0
1,TO,text,10,100,13.944999694824219,12.890999794006348,1.053999900817871,108.1762466430664
2,TO,text,10,100,13.36299991607666,12.890999794006348,0.4720001220703125,103.66146850585938
3,TO,text,10,100,13.079999923706055,12.890999794006348,0.18900012969970703,101.46614074707031
4,TO,text,10,100,12.770000457763672,12.890999794006348,-0.12099933624267578,99.06136322021484
5,TO,text,10,100,13.67199993133545,12.890999794006348,0.7810001373291016,106.05848693847656
6,TO,text,10,100,12.730999946594238,12.890999794006348,-0.15999984741210938,98.75881958007812
0,FROM,text,10,1000,15.336000442504883,15.336000442504883,0.0,100.0
1,FROM,text,10,1000,15.281000137329102,15.336000442504883,-0.05500030517578125,99.64136505126953
2,FROM,text,10,1000,15.225000381469727,15.336000442504883,-0.11100006103515625,99.27621459960938
3,FROM,text,10,1000,15.458000183105469,15.336000442504883,0.12199974060058594,100.7955093383789
4,FROM,text,10,1000,15.342000007629395,15.336000442504883,0.005999565124511719,100.03912353515625
5,FROM,text,10,1000,15.385000228881836,15.336000442504883,0.048999786376953125,100.31950378417969
6,FROM,text,10,1000,15.282999992370605,15.336000442504883,-0.053000450134277344,99.65440368652344
0,TO,text,10,1000,13.064000129699707,13.064000129699707,0.0,100.0
1,TO,text,10,1000,12.843999862670898,13.064000129699707,-0.2200002670288086,98.31597900390625
2,TO,text,10,1000,12.760000228881836,13.064000129699707,-0.3039999008178711,97.6729965209961
3,TO,text,10,1000,12.947999954223633,13.064000129699707,-0.11600017547607422,99.112060546875
4,TO,text,10,1000,12.83899974822998,13.064000129699707,-0.22500038146972656,98.27770233154297
5,TO,text,10,1000,13.720999717712402,13.064000129699707,0.6569995880126953,105.02908325195312
6,TO,text,10,1000,13.163999557495117,13.064000129699707,0.09999942779541016,100.76545715332031
0,FROM,text,10,10000,17.250999450683594,17.250999450683594,0.0,100.0
1,FROM,text,10,10000,17.194000244140625,17.250999450683594,-0.05699920654296875,99.66958618164062
2,FROM,text,10,10000,17.11050033569336,17.250999450683594,-0.14049911499023438,99.18556213378906
3,FROM,text,10,10000,17.180500030517578,17.250999450683594,-0.07049942016601562,99.5913314819336
4,FROM,text,10,10000,17.233999252319336,17.250999450683594,-0.017000198364257812,99.90145874023438
5,FROM,text,10,10000,17.233501434326172,17.250999450683594,-0.017498016357421875,99.89856719970703
6,FROM,text,10,10000,17.375,17.250999450683594,0.12400054931640625,100.71879577636719
0,TO,text,10,10000,14.88800048828125,14.88800048828125,0.0,100.0
1,TO,text,10,10000,14.92449951171875,14.88800048828125,0.0364990234375,100.24515533447266
2,TO,text,10,10000,14.812000274658203,14.88800048828125,-0.07600021362304688,99.4895248413086
3,TO,text,10,10000,14.9375,14.88800048828125,0.04949951171875,100.33247375488281
4,TO,text,10,10000,14.975000381469727,14.88800048828125,0.08699989318847656,100.58436584472656
5,TO,text,10,10000,14.798500061035156,14.88800048828125,-0.08950042724609375,99.39884185791016
6,TO,text,10,10000,14.954000473022461,14.88800048828125,0.06599998474121094,100.44331359863281
0,FROM,text,10,100000,34.97800064086914,34.97800064086914,0.0,100.0
1,FROM,text,10,100000,34.9739990234375,34.97800064086914,-0.004001617431640625,99.98856353759766
2,FROM,text,10,100000,34.792999267578125,34.97800064086914,-0.18500137329101562,99.4710922241211
3,FROM,text,10,100000,35.11199951171875,34.97800064086914,0.13399887084960938,100.38308715820312
4,FROM,text,10,100000,35.02199935913086,34.97800064086914,0.04399871826171875,100.12579345703125
5,FROM,text,10,100000,35.10900115966797,34.97800064086914,0.13100051879882812,100.37451934814453
6,FROM,text,10,100000,35.22700119018555,34.97800064086914,0.24900054931640625,100.71188354492188
0,TO,text,10,100000,34.20100021362305,34.20100021362305,0.0,100.0
1,TO,text,10,100000,34.25,34.20100021362305,0.048999786376953125,100.14326477050781
2,TO,text,10,100000,33.83100128173828,34.20100021362305,-0.3699989318847656,98.91816711425781
3,TO,text,10,100000,34.09000015258789,34.20100021362305,-0.11100006103515625,99.67544555664062
4,TO,text,10,100000,34.19900131225586,34.20100021362305,-0.0019989013671875,99.99415588378906
5,TO,text,10,100000,34.08700180053711,34.20100021362305,-0.1139984130859375,99.66667938232422
6,TO,text,10,100000,34.24399948120117,34.20100021362305,0.042999267578125,100.125732421875
0,FROM,text,10,1000000,211.42799377441406,211.42799377441406,0.0,100.0
1,FROM,text,10,1000000,211.6230010986328,211.42799377441406,0.19500732421875,100.09223175048828
2,FROM,text,10,1000000,210.42599487304688,211.42799377441406,-1.0019989013671875,99.52607727050781
3,FROM,text,10,1000000,212.6510009765625,211.42799377441406,1.2230072021484375,100.57845306396484
4,FROM,text,10,1000000,212.16000366210938,211.42799377441406,0.7320098876953125,100.34622192382812
5,FROM,text,10,1000000,212.00599670410156,211.42799377441406,0.5780029296875,100.27338409423828
6,FROM,text,10,1000000,211.95599365234375,211.42799377441406,0.5279998779296875,100.2497329711914
0,TO,text,10,1000000,220.22799682617188,220.22799682617188,0.0,100.0
1,TO,text,10,1000000,220.43800354003906,220.22799682617188,0.2100067138671875,100.09535217285156
2,TO,text,10,1000000,220.08299255371094,220.22799682617188,-0.1450042724609375,99.93415832519531
3,TO,text,10,1000000,220.8209991455078,220.22799682617188,0.5930023193359375,100.26927185058594
4,TO,text,10,1000000,220.99000549316406,220.22799682617188,0.7620086669921875,100.34600830078125
5,TO,text,10,1000000,220.2010040283203,220.22799682617188,-0.0269927978515625,99.98774719238281
6,TO,text,10,1000000,220.1269989013672,220.22799682617188,-0.1009979248046875,99.95413970947266
0,FROM,text,100,10,13.119999885559082,13.119999885559082,0.0,100.0
1,FROM,text,100,10,13.366000175476074,13.119999885559082,0.2460002899169922,101.87500762939453
2,FROM,text,100,10,13.418999671936035,13.119999885559082,0.2989997863769531,102.27896118164062
3,FROM,text,100,10,13.45199966430664,13.119999885559082,0.3319997787475586,102.5304946899414
4,FROM,text,100,10,13.428999900817871,13.119999885559082,0.30900001525878906,102.35517883300781
5,FROM,text,100,10,13.277999877929688,13.119999885559082,0.15799999237060547,101.20426177978516
6,FROM,text,100,10,13.378999710083008,13.119999885559082,0.2589998245239258,101.97408294677734
0,TO,text,100,10,12.909000396728516,12.909000396728516,0.0,100.0
1,TO,text,100,10,12.989999771118164,12.909000396728516,0.08099937438964844,100.62747192382812
2,TO,text,100,10,13.045999526977539,12.909000396728516,0.13699913024902344,101.06127166748047
3,TO,text,100,10,13.138999938964844,12.909000396728516,0.22999954223632812,101.78170013427734
4,TO,text,100,10,13.097000122070312,12.909000396728516,0.18799972534179688,101.45634460449219
5,TO,text,100,10,13.104000091552734,12.909000396728516,0.19499969482421875,101.51057434082031
6,TO,text,100,10,13.008999824523926,12.909000396728516,0.09999942779541016,100.77464294433594
0,FROM,text,100,100,13.423999786376953,13.423999786376953,0.0,100.0
1,FROM,text,100,100,13.690999984741211,13.423999786376953,0.2670001983642578,101.98896789550781
2,FROM,text,100,100,13.58899974822998,13.423999786376953,0.16499996185302734,101.22914123535156
3,FROM,text,100,100,13.704000473022461,13.423999786376953,0.2800006866455078,102.0858154296875
4,FROM,text,100,100,13.616000175476074,13.423999786376953,0.1920003890991211,101.4302749633789
5,FROM,text,100,100,13.619999885559082,13.423999786376953,0.1960000991821289,101.46007537841797
6,FROM,text,100,100,13.602999687194824,13.423999786376953,0.1789999008178711,101.33342742919922
0,TO,text,100,100,13.005999565124512,13.005999565124512,0.0,100.0
1,TO,text,100,100,13.125,13.005999565124512,0.11900043487548828,100.91497039794922
2,TO,text,100,100,13.166999816894531,13.005999565124512,0.16100025177001953,101.2378921508789
3,TO,text,100,100,13.182999610900879,13.005999565124512,0.1770000457763672,101.36090850830078
4,TO,text,100,100,13.232999801635742,13.005999565124512,0.22700023651123047,101.74535369873047
5,TO,text,100,100,13.107999801635742,13.005999565124512,0.10200023651123047,100.78425598144531
6,TO,text,100,100,13.138999938964844,13.005999565124512,0.13300037384033203,101.02261352539062
0,FROM,text,100,1000,15.298999786376953,15.298999786376953,0.0,100.0
1,FROM,text,100,1000,15.399999618530273,15.298999786376953,0.10099983215332031,100.66017150878906
2,FROM,text,100,1000,15.571999549865723,15.298999786376953,0.27299976348876953,101.78443145751953
3,FROM,text,100,1000,15.51099967956543,15.298999786376953,0.21199989318847656,101.38571166992188
4,FROM,text,100,1000,15.534000396728516,15.298999786376953,0.2350006103515625,101.53604888916016
5,FROM,text,100,1000,15.51099967956543,15.298999786376953,0.21199989318847656,101.38571166992188
6,FROM,text,100,1000,15.47599983215332,15.298999786376953,0.1770000457763672,101.15693664550781
0,TO,text,100,1000,14.425999641418457,14.425999641418457,0.0,100.0
1,TO,text,100,1000,14.458000183105469,14.425999641418457,0.03200054168701172,100.2218246459961
2,TO,text,100,1000,14.553000450134277,14.425999641418457,0.1270008087158203,100.88036346435547
3,TO,text,100,1000,14.503999710083008,14.425999641418457,0.07800006866455078,100.54068756103516
4,TO,text,100,1000,14.527000427246094,14.425999641418457,0.10100078582763672,100.70012664794922
5,TO,text,100,1000,14.416000366210938,14.425999641418457,-0.009999275207519531,99.9306869506836
6,TO,text,100,1000,14.520999908447266,14.425999641418457,0.0950002670288086,100.65853881835938
0,FROM,text,100,10000,29.645999908447266,29.645999908447266,0.0,100.0
1,FROM,text,100,10000,29.756500244140625,29.645999908447266,0.11050033569335938,100.37273406982422
2,FROM,text,100,10000,29.802000045776367,29.645999908447266,0.15600013732910156,100.52621459960938
3,FROM,text,100,10000,29.8075008392334,29.645999908447266,0.1615009307861328,100.54476165771484
4,FROM,text,100,10000,29.804000854492188,29.645999908447266,0.15800094604492188,100.532958984375
5,FROM,text,100,10000,29.86949920654297,29.645999908447266,0.22349929809570312,100.75389099121094
6,FROM,text,100,10000,29.77050018310547,29.645999908447266,0.12450027465820312,100.41995239257812
0,TO,text,100,10000,27.54599952697754,27.54599952697754,0.0,100.0
1,TO,text,100,10000,27.72650146484375,27.54599952697754,0.18050193786621094,100.6552734375
2,TO,text,100,10000,27.763999938964844,27.54599952697754,0.2180004119873047,100.7914047241211
3,TO,text,100,10000,27.790000915527344,27.54599952697754,0.2440013885498047,100.88579559326172
4,TO,text,100,10000,27.68199920654297,27.54599952697754,0.1359996795654297,100.49371337890625
5,TO,text,100,10000,27.76849937438965,27.54599952697754,0.22249984741210938,100.8077392578125
6,TO,text,100,10000,27.81800079345703,27.54599952697754,0.2720012664794922,100.9874496459961
0,FROM,text,100,100000,171.0989990234375,171.0989990234375,0.0,100.0
1,FROM,text,100,100000,171.19900512695312,171.0989990234375,0.100006103515625,100.0584487915039
2,FROM,text,100,100000,171.19900512695312,171.0989990234375,0.100006103515625,100.0584487915039
3,FROM,text,100,100000,171.26199340820312,171.0989990234375,0.162994384765625,100.09526062011719
4,FROM,text,100,100000,171.2989959716797,171.0989990234375,0.1999969482421875,100.11688232421875
5,FROM,text,100,100000,174.02999877929688,171.0989990234375,2.930999755859375,101.7130355834961
6,FROM,text,100,100000,171.26300048828125,171.0989990234375,0.16400146484375,100.09585571289062
0,TO,text,100,100000,158.3939971923828,158.3939971923828,0.0,100.0
1,TO,text,100,100000,158.28500366210938,158.3939971923828,-0.1089935302734375,99.93118286132812
2,TO,text,100,100000,158.3179931640625,158.3939971923828,-0.0760040283203125,99.95201873779297
3,TO,text,100,100000,158.35299682617188,158.3939971923828,-0.0410003662109375,99.97411346435547
4,TO,text,100,100000,158.64599609375,158.3939971923828,0.2519989013671875,100.15909576416016
5,TO,text,100,100000,158.33200073242188,158.3939971923828,-0.0619964599609375,99.96086120605469
6,TO,text,100,100000,158.37899780273438,158.3939971923828,-0.0149993896484375,99.99053192138672
0,FROM,text,100,1000000,1579.6939697265625,1579.6939697265625,0.0,100.0
1,FROM,text,100,1000000,1581.2149658203125,1579.6939697265625,1.52099609375,100.09628295898438
2,FROM,text,100,1000000,1578.7030029296875,1579.6939697265625,-0.990966796875,99.93726348876953
3,FROM,text,100,1000000,1579.676025390625,1579.6939697265625,-0.0179443359375,99.99886322021484
4,FROM,text,100,1000000,1579.7449951171875,1579.6939697265625,0.051025390625,100.00322723388672
5,FROM,text,100,1000000,1584.2249755859375,1579.6939697265625,4.531005859375,100.28682708740234
6,FROM,text,100,1000000,1582.5279541015625,1579.6939697265625,2.833984375,100.17939758300781
0,TO,text,100,1000000,1450.0250244140625,1450.0250244140625,0.0,100.0
1,TO,text,100,1000000,1450.1180419921875,1450.0250244140625,0.093017578125,100.00641632080078
2,TO,text,100,1000000,1449.7530517578125,1450.0250244140625,-0.27197265625,99.98123931884766
3,TO,text,100,1000000,1449.136962890625,1450.0250244140625,-0.8880615234375,99.93875885009766
4,TO,text,100,1000000,1449.9520263671875,1450.0250244140625,-0.072998046875,99.99496459960938
5,TO,text,100,1000000,1448.863037109375,1450.0250244140625,-1.1619873046875,99.91986083984375
6,TO,text,100,1000000,1449.7139892578125,1450.0250244140625,-0.31103515625,99.97854614257812
version,type,format,n_columns,n_rows,runtime,base_runtime,diff_runtime,diff_percentage
0,FROM,binary,1,10,13.225000381469727,13.225000381469727,0.0,100.0
1,FROM,binary,1,10,13.204999923706055,13.225000381469727,-0.020000457763671875,99.84876251220703
2,FROM,binary,1,10,13.21500015258789,13.225000381469727,-0.010000228881835938,99.92438507080078
3,FROM,binary,1,10,13.321000099182129,13.225000381469727,0.09599971771240234,100.72589874267578
4,FROM,binary,1,10,13.359000205993652,13.225000381469727,0.13399982452392578,101.01322937011719
5,FROM,binary,1,10,13.388999938964844,13.225000381469727,0.1639995574951172,101.24007415771484
6,FROM,binary,1,10,13.270999908447266,13.225000381469727,0.04599952697753906,100.34781646728516
0,TO,binary,1,10,12.965999603271484,12.965999603271484,0.0,100.0
1,TO,binary,1,10,12.918999671936035,12.965999603271484,-0.04699993133544922,99.63751220703125
2,TO,binary,1,10,12.937000274658203,12.965999603271484,-0.02899932861328125,99.7763442993164
3,TO,binary,1,10,12.98799991607666,12.965999603271484,0.02200031280517578,100.16968536376953
4,TO,binary,1,10,13.130999565124512,12.965999603271484,0.16499996185302734,101.2725601196289
5,TO,binary,1,10,13.083999633789062,12.965999603271484,0.11800003051757812,100.91006469726562
6,TO,binary,1,10,13.034000396728516,12.965999603271484,0.06800079345703125,100.52445220947266
0,FROM,binary,1,100,13.345000267028809,13.345000267028809,0.0,100.0
1,FROM,binary,1,100,13.279999732971191,13.345000267028809,-0.06500053405761719,99.51292419433594
2,FROM,binary,1,100,13.397000312805176,13.345000267028809,0.05200004577636719,100.38965606689453
3,FROM,binary,1,100,13.444000244140625,13.345000267028809,0.0989999771118164,100.74185180664062
4,FROM,binary,1,100,13.375,13.345000267028809,0.029999732971191406,100.22480773925781
5,FROM,binary,1,100,13.430000305175781,13.345000267028809,0.08500003814697266,100.63694763183594
6,FROM,binary,1,100,13.401000022888184,13.345000267028809,0.055999755859375,100.41963195800781
0,TO,binary,1,100,12.876999855041504,12.876999855041504,0.0,100.0
1,TO,binary,1,100,12.866000175476074,12.876999855041504,-0.010999679565429688,99.91458129882812
2,TO,binary,1,100,12.947999954223633,12.876999855041504,0.0710000991821289,100.5513687133789
3,TO,binary,1,100,13.057000160217285,12.876999855041504,0.18000030517578125,101.3978500366211
4,TO,binary,1,100,13.015000343322754,12.876999855041504,0.13800048828125,101.0716781616211
5,TO,binary,1,100,12.99899959564209,12.876999855041504,0.12199974060058594,100.94742584228516
6,TO,binary,1,100,13.008000373840332,12.876999855041504,0.13100051879882812,101.01731872558594
0,FROM,binary,1,1000,15.395000457763672,15.395000457763672,0.0,100.0
1,FROM,binary,1,1000,15.265000343322754,15.395000457763672,-0.13000011444091797,99.15557098388672
2,FROM,binary,1,1000,15.338000297546387,15.395000457763672,-0.057000160217285156,99.62974548339844
3,FROM,binary,1,1000,15.359000205993652,15.395000457763672,-0.03600025177001953,99.76615905761719
4,FROM,binary,1,1000,15.37399959564209,15.395000457763672,-0.02100086212158203,99.86358642578125
5,FROM,binary,1,1000,15.387999534606934,15.395000457763672,-0.007000923156738281,99.95452880859375
6,FROM,binary,1,1000,15.336000442504883,15.395000457763672,-0.05900001525878906,99.61676025390625
0,TO,binary,1,1000,13.090999603271484,13.090999603271484,0.0,100.0
1,TO,binary,1,1000,13.001999855041504,13.090999603271484,-0.08899974822998047,99.32014465332031
2,TO,binary,1,1000,12.97599983215332,13.090999603271484,-0.11499977111816406,99.12153625488281
3,TO,binary,1,1000,13.07699966430664,13.090999603271484,-0.01399993896484375,99.89305877685547
4,TO,binary,1,1000,13.152000427246094,13.090999603271484,0.061000823974609375,100.46598052978516
5,TO,binary,1,1000,13.017999649047852,13.090999603271484,-0.07299995422363281,99.4423599243164
6,TO,binary,1,1000,13.020999908447266,13.090999603271484,-0.06999969482421875,99.46528625488281
0,FROM,binary,1,10000,15.849499702453613,15.849499702453613,0.0,100.0
1,FROM,binary,1,10000,15.81049919128418,15.849499702453613,-0.039000511169433594,99.75393676757812
2,FROM,binary,1,10000,15.854000091552734,15.849499702453613,0.004500389099121094,100.02839660644531
3,FROM,binary,1,10000,15.87649917602539,15.849499702453613,0.026999473571777344,100.17034912109375
4,FROM,binary,1,10000,15.843000411987305,15.849499702453613,-0.006499290466308594,99.95899200439453
5,FROM,binary,1,10000,15.779999732971191,15.849499702453613,-0.06949996948242188,99.5615005493164
6,FROM,binary,1,10000,15.83650016784668,15.849499702453613,-0.012999534606933594,99.91798400878906
0,TO,binary,1,10000,13.947500228881836,13.947500228881836,0.0,100.0
1,TO,binary,1,10000,13.77199935913086,13.947500228881836,-0.17550086975097656,98.74170684814453
2,TO,binary,1,10000,13.874000549316406,13.947500228881836,-0.07349967956542969,99.4730224609375
3,TO,binary,1,10000,13.883500099182129,13.947500228881836,-0.06400012969970703,99.54113006591797
4,TO,binary,1,10000,13.875,13.947500228881836,-0.07250022888183594,99.48019409179688
5,TO,binary,1,10000,13.89799976348877,13.947500228881836,-0.049500465393066406,99.64509582519531
6,TO,binary,1,10000,13.931500434875488,13.947500228881836,-0.015999794006347656,99.88528442382812
0,FROM,binary,1,100000,20.225000381469727,20.225000381469727,0.0,100.0
1,FROM,binary,1,100000,20.45800018310547,20.225000381469727,0.2329998016357422,101.15203857421875
2,FROM,binary,1,100000,20.264999389648438,20.225000381469727,0.03999900817871094,100.19776916503906
3,FROM,binary,1,100000,20.30500030517578,20.225000381469727,0.07999992370605469,100.39554595947266
4,FROM,binary,1,100000,20.256999969482422,20.225000381469727,0.03199958801269531,100.15821838378906
5,FROM,binary,1,100000,20.145000457763672,20.225000381469727,-0.07999992370605469,99.60445404052734
6,FROM,binary,1,100000,20.29599952697754,20.225000381469727,0.0709991455078125,100.35104370117188
0,TO,binary,1,100000,22.038000106811523,22.038000106811523,0.0,100.0
1,TO,binary,1,100000,21.944000244140625,22.038000106811523,-0.09399986267089844,99.5734634399414
2,TO,binary,1,100000,22.017000198364258,22.038000106811523,-0.020999908447265625,99.90470886230469
3,TO,binary,1,100000,22.113000869750977,22.038000106811523,0.07500076293945312,100.34033203125
4,TO,binary,1,100000,22.079999923706055,22.038000106811523,0.04199981689453125,100.19058227539062
5,TO,binary,1,100000,22.018999099731445,22.038000106811523,-0.019001007080078125,99.91378021240234
6,TO,binary,1,100000,22.05699920654297,22.038000106811523,0.018999099731445312,100.08621215820312
0,FROM,binary,1,1000000,64.64900207519531,64.64900207519531,0.0,100.0
1,FROM,binary,1,1000000,66.31199645996094,64.64900207519531,1.662994384765625,102.57234191894531
2,FROM,binary,1,1000000,64.19599914550781,64.64900207519531,-0.4530029296875,99.29928588867188
3,FROM,binary,1,1000000,65.16200256347656,64.64900207519531,0.51300048828125,100.79351806640625
4,FROM,binary,1,1000000,64.18000030517578,64.64900207519531,-0.46900177001953125,99.2745361328125
5,FROM,binary,1,1000000,63.731998443603516,64.64900207519531,-0.9170036315917969,98.5815658569336
6,FROM,binary,1,1000000,63.641998291015625,64.64900207519531,-1.0070037841796875,98.44235229492188
0,TO,binary,1,1000000,100.6719970703125,100.6719970703125,0.0,100.0
1,TO,binary,1,1000000,100.6449966430664,100.6719970703125,-0.02700042724609375,99.97317504882812
2,TO,binary,1,1000000,100.62300109863281,100.6719970703125,-0.0489959716796875,99.95133209228516
3,TO,binary,1,1000000,100.66500091552734,100.6719970703125,-0.00699615478515625,99.99304962158203
4,TO,binary,1,1000000,101.02400207519531,100.6719970703125,0.3520050048828125,100.34965515136719
5,TO,binary,1,1000000,100.42400360107422,100.6719970703125,-0.24799346923828125,99.753662109375
6,TO,binary,1,1000000,100.96399688720703,100.6719970703125,0.29199981689453125,100.29004669189453
0,FROM,binary,10,10,13.314000129699707,13.314000129699707,0.0,100.0
1,FROM,binary,10,10,13.180000305175781,13.314000129699707,-0.13399982452392578,98.99353790283203
2,FROM,binary,10,10,13.25100040435791,13.314000129699707,-0.06299972534179688,99.52681732177734
3,FROM,binary,10,10,13.229000091552734,13.314000129699707,-0.08500003814697266,99.361572265625
4,FROM,binary,10,10,13.468999862670898,13.314000129699707,0.1549997329711914,101.1641845703125
5,FROM,binary,10,10,13.307000160217285,13.314000129699707,-0.006999969482421875,99.94742584228516
6,FROM,binary,10,10,13.274999618530273,13.314000129699707,-0.039000511169433594,99.70706939697266
0,TO,binary,10,10,12.998000144958496,12.998000144958496,0.0,100.0
1,TO,binary,10,10,12.970000267028809,12.998000144958496,-0.0279998779296875,99.78458404541016
2,TO,binary,10,10,12.892999649047852,12.998000144958496,-0.10500049591064453,99.19217681884766
3,TO,binary,10,10,13.001999855041504,12.998000144958496,0.0039997100830078125,100.03076934814453
4,TO,binary,10,10,13.005999565124512,12.998000144958496,0.007999420166015625,100.0615463256836
5,TO,binary,10,10,12.968999862670898,12.998000144958496,-0.029000282287597656,99.77688598632812
6,TO,binary,10,10,12.998000144958496,12.998000144958496,0.0,100.0
0,FROM,binary,10,100,13.411999702453613,13.411999702453613,0.0,100.0
1,FROM,binary,10,100,13.454000473022461,13.411999702453613,0.042000770568847656,100.31316375732422
2,FROM,binary,10,100,13.402000427246094,13.411999702453613,-0.009999275207519531,99.92544555664062
3,FROM,binary,10,100,13.38599967956543,13.411999702453613,-0.026000022888183594,99.80614471435547
4,FROM,binary,10,100,13.38599967956543,13.411999702453613,-0.026000022888183594,99.80614471435547
5,FROM,binary,10,100,13.388999938964844,13.411999702453613,-0.02299976348876953,99.8285140991211
6,FROM,binary,10,100,13.399999618530273,13.411999702453613,-0.012000083923339844,99.91053009033203
0,TO,binary,10,100,12.946000099182129,12.946000099182129,0.0,100.0
1,TO,binary,10,100,12.914999961853027,12.946000099182129,-0.031000137329101562,99.76054382324219
2,TO,binary,10,100,12.986000061035156,12.946000099182129,0.039999961853027344,100.30897521972656
3,TO,binary,10,100,13.130000114440918,12.946000099182129,0.18400001525878906,101.4212875366211
4,TO,binary,10,100,13.083000183105469,12.946000099182129,0.13700008392333984,101.05824279785156
5,TO,binary,10,100,13.034000396728516,12.946000099182129,0.08800029754638672,100.67974090576172
6,TO,binary,10,100,13.022000312805176,12.946000099182129,0.07600021362304688,100.5870590209961
0,FROM,binary,10,1000,15.5,15.5,0.0,100.0
1,FROM,binary,10,1000,15.447999954223633,15.5,-0.05200004577636719,99.66451263427734
2,FROM,binary,10,1000,15.47599983215332,15.5,-0.024000167846679688,99.84516143798828
3,FROM,binary,10,1000,15.572999954223633,15.5,0.07299995422363281,100.4709701538086
4,FROM,binary,10,1000,15.567000389099121,15.5,0.0670003890991211,100.43226623535156
5,FROM,binary,10,1000,15.51200008392334,15.5,0.012000083923339844,100.0774154663086
6,FROM,binary,10,1000,15.503000259399414,15.5,0.0030002593994140625,100.01936340332031
0,TO,binary,10,1000,13.291000366210938,13.291000366210938,0.0,100.0
1,TO,binary,10,1000,13.319000244140625,13.291000366210938,0.0279998779296875,100.21066284179688
2,TO,binary,10,1000,13.21500015258789,13.291000366210938,-0.07600021362304688,99.42818450927734
3,TO,binary,10,1000,13.300000190734863,13.291000366210938,0.008999824523925781,100.06771087646484
4,TO,binary,10,1000,13.255999565124512,13.291000366210938,-0.03500080108642578,99.73666381835938
5,TO,binary,10,1000,13.29800033569336,13.291000366210938,0.006999969482421875,100.05266571044922
6,TO,binary,10,1000,13.229999542236328,13.291000366210938,-0.061000823974609375,99.5410385131836
0,FROM,binary,10,10000,17.199499130249023,17.199499130249023,0.0,100.0
1,FROM,binary,10,10000,17.166000366210938,17.199499130249023,-0.03349876403808594,99.80523681640625
2,FROM,binary,10,10000,17.038999557495117,17.199499130249023,-0.16049957275390625,99.06683349609375
3,FROM,binary,10,10000,17.116500854492188,17.199499130249023,-0.08299827575683594,99.51744079589844
4,FROM,binary,10,10000,17.158000946044922,17.199499130249023,-0.04149818420410156,99.75872802734375
5,FROM,binary,10,10000,17.147499084472656,17.199499130249023,-0.05200004577636719,99.69766998291016
6,FROM,binary,10,10000,17.186500549316406,17.199499130249023,-0.012998580932617188,99.92443084716797
0,TO,binary,10,10000,16.144500732421875,16.144500732421875,0.0,100.0
1,TO,binary,10,10000,16.118499755859375,16.144500732421875,-0.0260009765625,99.83895111083984
2,TO,binary,10,10000,16.192001342773438,16.144500732421875,0.0475006103515625,100.29421997070312
3,TO,binary,10,10000,16.203998565673828,16.144500732421875,0.059497833251953125,100.36853790283203
4,TO,binary,10,10000,16.220500946044922,16.144500732421875,0.07600021362304688,100.47074890136719
5,TO,binary,10,10000,16.159000396728516,16.144500732421875,0.014499664306640625,100.08981323242188
6,TO,binary,10,10000,16.174999237060547,16.144500732421875,0.030498504638671875,100.18891143798828
0,FROM,binary,10,100000,33.07899856567383,33.07899856567383,0.0,100.0
1,FROM,binary,10,100000,33.816001892089844,33.07899856567383,0.7370033264160156,102.22801208496094
2,FROM,binary,10,100000,32.86800003051758,33.07899856567383,-0.21099853515625,99.36213684082031
3,FROM,binary,10,100000,32.95000076293945,33.07899856567383,-0.128997802734375,99.61003112792969
4,FROM,binary,10,100000,32.81999969482422,33.07899856567383,-0.2589988708496094,99.21702575683594
5,FROM,binary,10,100000,32.84000015258789,33.07899856567383,-0.2389984130859375,99.2774887084961
6,FROM,binary,10,100000,32.82699966430664,33.07899856567383,-0.2519989013671875,99.23818969726562
0,TO,binary,10,100000,44.1870002746582,44.1870002746582,0.0,100.0
1,TO,binary,10,100000,44.15999984741211,44.1870002746582,-0.02700042724609375,99.93889617919922
2,TO,binary,10,100000,44.231998443603516,44.1870002746582,0.0449981689453125,100.10183715820312
3,TO,binary,10,100000,44.41299819946289,44.1870002746582,0.2259979248046875,100.51145935058594
4,TO,binary,10,100000,44.31399917602539,44.1870002746582,0.1269989013671875,100.28741455078125
5,TO,binary,10,100000,44.345001220703125,44.1870002746582,0.15800094604492188,100.3575668334961
6,TO,binary,10,100000,44.367000579833984,44.1870002746582,0.18000030517578125,100.40736389160156
0,FROM,binary,10,1000000,187.4199981689453,187.4199981689453,0.0,100.0
1,FROM,binary,10,1000000,197.552001953125,187.4199981689453,10.132003784179688,105.40604400634766
2,FROM,binary,10,1000000,186.0290069580078,187.4199981689453,-1.3909912109375,99.25782012939453
3,FROM,binary,10,1000000,186.86099243164062,187.4199981689453,-0.5590057373046875,99.70173645019531
4,FROM,binary,10,1000000,186.0189971923828,187.4199981689453,-1.4010009765625,99.25247955322266
5,FROM,binary,10,1000000,185.9709930419922,187.4199981689453,-1.449005126953125,99.22686767578125
6,FROM,binary,10,1000000,186.95599365234375,187.4199981689453,-0.4640045166015625,99.75242614746094
0,TO,binary,10,1000000,321.8900146484375,321.8900146484375,0.0,100.0
1,TO,binary,10,1000000,321.87701416015625,321.8900146484375,-0.01300048828125,99.99595642089844
2,TO,binary,10,1000000,321.0559997558594,321.8900146484375,-0.834014892578125,99.74089813232422
3,TO,binary,10,1000000,322.1109924316406,321.8900146484375,0.220977783203125,100.06864929199219
4,TO,binary,10,1000000,321.9859924316406,321.8900146484375,0.095977783203125,100.02981567382812
5,TO,binary,10,1000000,322.9639892578125,321.8900146484375,1.073974609375,100.3336410522461
6,TO,binary,10,1000000,327.9700012207031,321.8900146484375,6.079986572265625,101.88883209228516
0,FROM,binary,100,10,13.416999816894531,13.416999816894531,0.0,100.0
1,FROM,binary,100,10,13.42300033569336,13.416999816894531,0.006000518798828125,100.04472351074219
2,FROM,binary,100,10,13.355999946594238,13.416999816894531,-0.06099987030029297,99.54535675048828
3,FROM,binary,100,10,13.352999687194824,13.416999816894531,-0.06400012969970703,99.52298736572266
4,FROM,binary,100,10,13.402000427246094,13.416999816894531,-0.0149993896484375,99.8882064819336
5,FROM,binary,100,10,13.317999839782715,13.416999816894531,-0.0989999771118164,99.26213073730469
6,FROM,binary,100,10,13.980999946594238,13.416999816894531,0.564000129699707,104.20362091064453
0,TO,binary,100,10,13.119000434875488,13.119000434875488,0.0,100.0
1,TO,binary,100,10,13.036999702453613,13.119000434875488,-0.082000732421875,99.37494659423828
2,TO,binary,100,10,13.031999588012695,13.119000434875488,-0.08700084686279297,99.33683013916016
3,TO,binary,100,10,13.055999755859375,13.119000434875488,-0.06300067901611328,99.519775390625
4,TO,binary,100,10,13.128000259399414,13.119000434875488,0.008999824523925781,100.068603515625
5,TO,binary,100,10,13.17300033569336,13.119000434875488,0.053999900817871094,100.41162109375
6,TO,binary,100,10,13.991999626159668,13.119000434875488,0.8729991912841797,106.65446472167969
0,FROM,binary,100,100,13.508999824523926,13.508999824523926,0.0,100.0
1,FROM,binary,100,100,13.522000312805176,13.508999824523926,0.01300048828125,100.09623718261719
2,FROM,binary,100,100,13.661999702453613,13.508999824523926,0.1529998779296875,101.132568359375
3,FROM,binary,100,100,13.595999717712402,13.508999824523926,0.08699989318847656,100.64401245117188
4,FROM,binary,100,100,13.593999862670898,13.508999824523926,0.08500003814697266,100.62921142578125
5,FROM,binary,100,100,13.642999649047852,13.508999824523926,0.13399982452392578,100.99192810058594
6,FROM,binary,100,100,14.355999946594238,13.508999824523926,0.8470001220703125,106.2698974609375
0,TO,binary,100,100,13.321000099182129,13.321000099182129,0.0,100.0
1,TO,binary,100,100,13.154000282287598,13.321000099182129,-0.16699981689453125,98.746337890625
2,TO,binary,100,100,13.159000396728516,13.321000099182129,-0.16199970245361328,98.78387451171875
3,TO,binary,100,100,13.300000190734863,13.321000099182129,-0.020999908447265625,99.84236145019531
4,TO,binary,100,100,13.39799976348877,13.321000099182129,0.07699966430664062,100.57803344726562
5,TO,binary,100,100,13.239999771118164,13.321000099182129,-0.08100032806396484,99.39193725585938
6,TO,binary,100,100,14.071000099182129,13.321000099182129,0.75,105.63020324707031
0,FROM,binary,100,1000,17.107999801635742,17.107999801635742,0.0,100.0
1,FROM,binary,100,1000,17.222000122070312,17.107999801635742,0.11400032043457031,100.6663589477539
2,FROM,binary,100,1000,17.104999542236328,17.107999801635742,-0.0030002593994140625,99.98246765136719
3,FROM,binary,100,1000,17.125999450683594,17.107999801635742,0.017999649047851562,100.10521697998047
4,FROM,binary,100,1000,17.155000686645508,17.107999801635742,0.047000885009765625,100.27472686767578
5,FROM,binary,100,1000,17.128999710083008,17.107999801635742,0.020999908447265625,100.12274932861328
6,FROM,binary,100,1000,17.11400032043457,17.107999801635742,0.006000518798828125,100.03507232666016
0,TO,binary,100,1000,15.152999877929688,15.152999877929688,0.0,100.0
1,TO,binary,100,1000,15.17199993133545,15.152999877929688,0.01900005340576172,100.12538146972656
2,TO,binary,100,1000,15.343000411987305,15.152999877929688,0.1900005340576172,101.25387573242188
3,TO,binary,100,1000,15.336999893188477,15.152999877929688,0.18400001525878906,101.21427917480469
4,TO,binary,100,1000,15.385000228881836,15.152999877929688,0.23200035095214844,101.53105163574219
5,TO,binary,100,1000,15.222999572753906,15.152999877929688,0.06999969482421875,100.46194458007812
6,TO,binary,100,1000,15.357999801635742,15.152999877929688,0.2049999237060547,101.35286712646484
0,FROM,binary,100,10000,29.92300033569336,29.92300033569336,0.0,100.0
1,FROM,binary,100,10000,31.05699920654297,29.92300033569336,1.1339988708496094,103.78972625732422
2,FROM,binary,100,10000,29.880001068115234,29.92300033569336,-0.042999267578125,99.8563003540039
3,FROM,binary,100,10000,29.976001739501953,29.92300033569336,0.05300140380859375,100.1771240234375
4,FROM,binary,100,10000,29.98200035095215,29.92300033569336,0.05900001525878906,100.19717407226562
5,FROM,binary,100,10000,29.909000396728516,29.92300033569336,-0.01399993896484375,99.95321655273438
6,FROM,binary,100,10000,29.975000381469727,29.92300033569336,0.05200004577636719,100.17378234863281
0,TO,binary,100,10000,35.33100128173828,35.33100128173828,0.0,100.0
1,TO,binary,100,10000,35.240501403808594,35.33100128173828,-0.0904998779296875,99.74385070800781
2,TO,binary,100,10000,35.27149963378906,35.33100128173828,-0.05950164794921875,99.83158874511719
3,TO,binary,100,10000,35.35099792480469,35.33100128173828,0.01999664306640625,100.05660247802734
4,TO,binary,100,10000,35.30950164794922,35.33100128173828,-0.0214996337890625,99.93914794921875
5,TO,binary,100,10000,35.33799743652344,35.33100128173828,0.00699615478515625,100.0197982788086
6,TO,binary,100,10000,35.316001892089844,35.33100128173828,-0.0149993896484375,99.9575424194336
0,FROM,binary,100,100000,154.2100067138672,154.2100067138672,0.0,100.0
1,FROM,binary,100,100000,165.51499938964844,154.2100067138672,11.30499267578125,107.3309097290039
2,FROM,binary,100,100000,154.08599853515625,154.2100067138672,-0.1240081787109375,99.91958618164062
3,FROM,binary,100,100000,154.16900634765625,154.2100067138672,-0.0410003662109375,99.9734115600586
4,FROM,binary,100,100000,154.16700744628906,154.2100067138672,-0.042999267578125,99.97211456298828
5,FROM,binary,100,100000,154.42100524902344,154.2100067138672,0.21099853515625,100.13682556152344
6,FROM,binary,100,100000,154.3509979248047,154.2100067138672,0.1409912109375,100.0914306640625
0,TO,binary,100,100000,234.04600524902344,234.04600524902344,0.0,100.0
1,TO,binary,100,100000,233.58599853515625,234.04600524902344,-0.4600067138671875,99.80345153808594
2,TO,binary,100,100000,233.3249969482422,234.04600524902344,-0.72100830078125,99.69194030761719
3,TO,binary,100,100000,235.11000061035156,234.04600524902344,1.063995361328125,100.45460510253906
4,TO,binary,100,100000,233.48300170898438,234.04600524902344,-0.5630035400390625,99.75944519042969
5,TO,binary,100,100000,234.45799255371094,234.04600524902344,0.4119873046875,100.176025390625
6,TO,binary,100,100000,235.2729949951172,234.04600524902344,1.22698974609375,100.52424621582031
0,FROM,binary,100,1000000,1395.2139892578125,1395.2139892578125,0.0,100.0
1,FROM,binary,100,1000000,1508.948974609375,1395.2139892578125,113.7349853515625,108.15179443359375
2,FROM,binary,100,1000000,1394.416015625,1395.2139892578125,-0.7979736328125,99.94280242919922
3,FROM,binary,100,1000000,1395.1190185546875,1395.2139892578125,-0.094970703125,99.99319458007812
4,FROM,binary,100,1000000,1394.0909423828125,1395.2139892578125,-1.123046875,99.91950988769531
5,FROM,binary,100,1000000,1396.2349853515625,1395.2139892578125,1.02099609375,100.07318115234375
6,FROM,binary,100,1000000,1411.261962890625,1395.2139892578125,16.0479736328125,101.15021514892578
0,TO,binary,100,1000000,2195.716064453125,2195.716064453125,0.0,100.0
1,TO,binary,100,1000000,2193.77294921875,2195.716064453125,-1.943115234375,99.91150665283203
2,TO,binary,100,1000000,2190.577880859375,2195.716064453125,-5.13818359375,99.7659912109375
3,TO,binary,100,1000000,2203.133056640625,2195.716064453125,7.4169921875,100.3377914428711
4,TO,binary,100,1000000,2194.1220703125,2195.716064453125,-1.593994140625,99.92739868164062
5,TO,binary,100,1000000,2204.04296875,2195.716064453125,8.326904296875,100.37922668457031
6,TO,binary,100,1000000,2225.094970703125,2195.716064453125,29.37890625,101.33800506591797
0,FROM,csv,1,10,13.336999893188477,13.336999893188477,0.0,100.0
1,FROM,csv,1,10,13.192000389099121,13.336999893188477,-0.14499950408935547,98.91280364990234
2,FROM,csv,1,10,13.258999824523926,13.336999893188477,-0.07800006866455078,99.4151611328125
3,FROM,csv,1,10,13.321000099182129,13.336999893188477,-0.015999794006347656,99.88003540039062
4,FROM,csv,1,10,13.286999702453613,13.336999893188477,-0.05000019073486328,99.6250991821289
5,FROM,csv,1,10,13.282999992370605,13.336999893188477,-0.053999900817871094,99.59510803222656
6,FROM,csv,1,10,13.213000297546387,13.336999893188477,-0.12399959564208984,99.07025909423828
0,TO,csv,1,10,12.958000183105469,12.958000183105469,0.0,100.0
1,TO,csv,1,10,12.984999656677246,12.958000183105469,0.026999473571777344,100.20836639404297
2,TO,csv,1,10,12.970999717712402,12.958000183105469,0.012999534606933594,100.10031127929688
3,TO,csv,1,10,13.010000228881836,12.958000183105469,0.05200004577636719,100.40129089355469
4,TO,csv,1,10,13.090999603271484,12.958000183105469,0.13299942016601562,101.0263900756836
5,TO,csv,1,10,13.036999702453613,12.958000183105469,0.07899951934814453,100.60965728759766
6,TO,csv,1,10,13.005999565124512,12.958000183105469,0.04799938201904297,100.37042236328125
0,FROM,csv,1,100,13.437999725341797,13.437999725341797,0.0,100.0
1,FROM,csv,1,100,13.359000205993652,13.437999725341797,-0.07899951934814453,99.41211700439453
2,FROM,csv,1,100,13.446000099182129,13.437999725341797,0.008000373840332031,100.05953216552734
3,FROM,csv,1,100,13.428999900817871,13.437999725341797,-0.008999824523925781,99.93302917480469
4,FROM,csv,1,100,13.38700008392334,13.437999725341797,-0.05099964141845703,99.62047576904297
5,FROM,csv,1,100,13.406000137329102,13.437999725341797,-0.03199958801269531,99.76187133789062
6,FROM,csv,1,100,13.444999694824219,13.437999725341797,0.006999969482421875,100.05209350585938
0,TO,csv,1,100,12.979999542236328,12.979999542236328,0.0,100.0
1,TO,csv,1,100,12.892999649047852,12.979999542236328,-0.08699989318847656,99.32974243164062
2,TO,csv,1,100,12.937999725341797,12.979999542236328,-0.04199981689453125,99.67642211914062
3,TO,csv,1,100,12.958999633789062,12.979999542236328,-0.020999908447265625,99.83821868896484
4,TO,csv,1,100,13.027000427246094,12.979999542236328,0.047000885009765625,100.36209869384766
5,TO,csv,1,100,12.968000411987305,12.979999542236328,-0.011999130249023438,99.90756225585938
6,TO,csv,1,100,12.982999801635742,12.979999542236328,0.0030002593994140625,100.02311706542969
0,FROM,csv,1,1000,15.378999710083008,15.378999710083008,0.0,100.0
1,FROM,csv,1,1000,15.586999893188477,15.378999710083008,0.20800018310546875,101.35248565673828
2,FROM,csv,1,1000,15.387999534606934,15.378999710083008,0.008999824523925781,100.05851745605469
3,FROM,csv,1,1000,15.529000282287598,15.378999710083008,0.15000057220458984,100.97535705566406
4,FROM,csv,1,1000,15.46399974822998,15.378999710083008,0.08500003814697266,100.55270385742188
5,FROM,csv,1,1000,15.480999946594238,15.378999710083008,0.10200023651123047,100.66324615478516
6,FROM,csv,1,1000,15.508999824523926,15.378999710083008,0.13000011444091797,100.8453140258789
0,TO,csv,1,1000,13.08899974822998,13.08899974822998,0.0,100.0
1,TO,csv,1,1000,12.984000205993652,13.08899974822998,-0.10499954223632812,99.19780731201172
2,TO,csv,1,1000,13.08899974822998,13.08899974822998,0.0,100.0
3,TO,csv,1,1000,13.156000137329102,13.08899974822998,0.0670003890991211,100.51188659667969
4,TO,csv,1,1000,13.14799976348877,13.08899974822998,0.05900001525878906,100.45076751708984
5,TO,csv,1,1000,13.08899974822998,13.08899974822998,0.0,100.0
6,TO,csv,1,1000,13.10099983215332,13.08899974822998,0.012000083923339844,100.09168243408203
0,FROM,csv,1,10000,15.961999893188477,15.961999893188477,0.0,100.0
1,FROM,csv,1,10000,15.958000183105469,15.961999893188477,-0.0039997100830078125,99.97494506835938
2,FROM,csv,1,10000,15.934000015258789,15.961999893188477,-0.0279998779296875,99.8245849609375
3,FROM,csv,1,10000,16.01150131225586,15.961999893188477,0.04950141906738281,100.31011962890625
4,FROM,csv,1,10000,16.089000701904297,15.961999893188477,0.1270008087158203,100.795654296875
5,FROM,csv,1,10000,16.045501708984375,15.961999893188477,0.08350181579589844,100.52312469482422
6,FROM,csv,1,10000,15.97800064086914,15.961999893188477,0.016000747680664062,100.1002426147461
0,TO,csv,1,10000,13.887500762939453,13.887500762939453,0.0,100.0
1,TO,csv,1,10000,13.811500549316406,13.887500762939453,-0.07600021362304688,99.45274353027344
2,TO,csv,1,10000,13.842500686645508,13.887500762939453,-0.04500007629394531,99.67596435546875
3,TO,csv,1,10000,13.960000038146973,13.887500762939453,0.07249927520751953,100.52204132080078
4,TO,csv,1,10000,13.864500045776367,13.887500762939453,-0.023000717163085938,99.8343734741211
5,TO,csv,1,10000,13.90999984741211,13.887500762939453,0.02249908447265625,100.16200256347656
6,TO,csv,1,10000,13.848999977111816,13.887500762939453,-0.03850078582763672,99.72276306152344
0,FROM,csv,1,100000,21.46299934387207,21.46299934387207,0.0,100.0
1,FROM,csv,1,100000,21.44300079345703,21.46299934387207,-0.019998550415039062,99.90682983398438
2,FROM,csv,1,100000,21.88599967956543,21.46299934387207,0.4230003356933594,101.97084045410156
3,FROM,csv,1,100000,22.055999755859375,21.46299934387207,0.5930004119873047,102.76290130615234
4,FROM,csv,1,100000,21.66699981689453,21.46299934387207,0.20400047302246094,100.95047760009766
5,FROM,csv,1,100000,21.586000442504883,21.46299934387207,0.1230010986328125,100.57308959960938
6,FROM,csv,1,100000,21.58300018310547,21.46299934387207,0.12000083923339844,100.5591049194336
0,TO,csv,1,100000,21.773000717163086,21.773000717163086,0.0,100.0
1,TO,csv,1,100000,21.756000518798828,21.773000717163086,-0.017000198364257812,99.92192077636719
2,TO,csv,1,100000,21.844999313354492,21.773000717163086,0.07199859619140625,100.33067321777344
3,TO,csv,1,100000,21.81399917602539,21.773000717163086,0.04099845886230469,100.18830108642578
4,TO,csv,1,100000,21.924999237060547,21.773000717163086,0.15199851989746094,100.69810485839844
5,TO,csv,1,100000,21.697999954223633,21.773000717163086,-0.07500076293945312,99.65553283691406
6,TO,csv,1,100000,21.680999755859375,21.773000717163086,-0.09200096130371094,99.57745361328125
0,FROM,csv,1,1000000,77.03500366210938,77.03500366210938,0.0,100.0
1,FROM,csv,1,1000000,77.24600219726562,77.03500366210938,0.21099853515625,100.27389526367188
2,FROM,csv,1,1000000,78.69499969482422,77.03500366210938,1.6599960327148438,102.15486145019531
3,FROM,csv,1,1000000,80.91799926757812,77.03500366210938,3.88299560546875,105.04056549072266
4,FROM,csv,1,1000000,77.97699737548828,77.03500366210938,0.9419937133789062,101.22281646728516
5,FROM,csv,1,1000000,77.552001953125,77.03500366210938,0.516998291015625,100.67112731933594
6,FROM,csv,1,1000000,77.61399841308594,77.03500366210938,0.5789947509765625,100.75160217285156
0,TO,csv,1,1000000,98.54100036621094,98.54100036621094,0.0,100.0
1,TO,csv,1,1000000,98.0250015258789,98.54100036621094,-0.5159988403320312,99.47636413574219
2,TO,csv,1,1000000,98.15299987792969,98.54100036621094,-0.38800048828125,99.60625457763672
3,TO,csv,1,1000000,98.12100219726562,98.54100036621094,-0.4199981689453125,99.57378387451172
4,TO,csv,1,1000000,99.13600158691406,98.54100036621094,0.595001220703125,100.60380554199219
5,TO,csv,1,1000000,97.93800354003906,98.54100036621094,-0.602996826171875,99.38807678222656
6,TO,csv,1,1000000,97.73899841308594,98.54100036621094,-0.802001953125,99.18611907958984
0,FROM,csv,10,10,13.223999977111816,13.223999977111816,0.0,100.0
1,FROM,csv,10,10,13.300000190734863,13.223999977111816,0.07600021362304688,100.57472229003906
2,FROM,csv,10,10,13.293999671936035,13.223999977111816,0.06999969482421875,100.52933502197266
3,FROM,csv,10,10,13.253999710083008,13.223999977111816,0.029999732971191406,100.22685241699219
4,FROM,csv,10,10,13.388999938964844,13.223999977111816,0.16499996185302734,101.24772644042969
5,FROM,csv,10,10,13.324000358581543,13.223999977111816,0.10000038146972656,100.7562026977539
6,FROM,csv,10,10,13.312999725341797,13.223999977111816,0.08899974822998047,100.67301940917969
0,TO,csv,10,10,12.982999801635742,12.982999801635742,0.0,100.0
1,TO,csv,10,10,12.913000106811523,12.982999801635742,-0.06999969482421875,99.46083068847656
2,TO,csv,10,10,13.081999778747559,12.982999801635742,0.0989999771118164,100.76253509521484
3,TO,csv,10,10,13.013999938964844,12.982999801635742,0.031000137329101562,100.23877716064453
4,TO,csv,10,10,13.0649995803833,12.982999801635742,0.0819997787475586,100.631591796875
5,TO,csv,10,10,13.020999908447266,12.982999801635742,0.03800010681152344,100.29269409179688
6,TO,csv,10,10,12.911999702453613,12.982999801635742,-0.0710000991821289,99.453125
0,FROM,csv,10,100,13.354000091552734,13.354000091552734,0.0,100.0
1,FROM,csv,10,100,13.392000198364258,13.354000091552734,0.03800010681152344,100.28456115722656
2,FROM,csv,10,100,13.397000312805176,13.354000091552734,0.043000221252441406,100.32200622558594
3,FROM,csv,10,100,13.434000015258789,13.354000091552734,0.07999992370605469,100.59907531738281
4,FROM,csv,10,100,13.496000289916992,13.354000091552734,0.1420001983642578,101.06336212158203
5,FROM,csv,10,100,13.458999633789062,13.354000091552734,0.10499954223632812,100.7862777709961
6,FROM,csv,10,100,13.420000076293945,13.354000091552734,0.06599998474121094,100.49423217773438
0,TO,csv,10,100,12.928000450134277,12.928000450134277,0.0,100.0
1,TO,csv,10,100,13.008999824523926,12.928000450134277,0.08099937438964844,100.62654113769531
2,TO,csv,10,100,13.02400016784668,12.928000450134277,0.09599971771240234,100.74256896972656
3,TO,csv,10,100,13.039999961853027,12.928000450134277,0.11199951171875,100.8663330078125
4,TO,csv,10,100,13.045000076293945,12.928000450134277,0.11699962615966797,100.90501403808594
5,TO,csv,10,100,13.053000450134277,12.928000450134277,0.125,100.9668960571289
6,TO,csv,10,100,13.079999923706055,12.928000450134277,0.15199947357177734,101.17573547363281
0,FROM,csv,10,1000,15.607000350952148,15.607000350952148,0.0,100.0
1,FROM,csv,10,1000,15.53499984741211,15.607000350952148,-0.07200050354003906,99.53866577148438
2,FROM,csv,10,1000,15.793000221252441,15.607000350952148,0.18599987030029297,101.1917724609375
3,FROM,csv,10,1000,15.74899959564209,15.607000350952148,0.1419992446899414,100.90984344482422
4,FROM,csv,10,1000,15.73900032043457,15.607000350952148,0.13199996948242188,100.84577941894531
5,FROM,csv,10,1000,15.72599983215332,15.607000350952148,0.11899948120117188,100.7624740600586
6,FROM,csv,10,1000,15.611000061035156,15.607000350952148,0.0039997100830078125,100.02562713623047
0,TO,csv,10,1000,13.270999908447266,13.270999908447266,0.0,100.0
1,TO,csv,10,1000,13.159000396728516,13.270999908447266,-0.11199951171875,99.15605926513672
2,TO,csv,10,1000,13.14799976348877,13.270999908447266,-0.1230001449584961,99.07316589355469
3,TO,csv,10,1000,13.27299976348877,13.270999908447266,0.0019998550415039062,100.01506805419922
4,TO,csv,10,1000,13.251999855041504,13.270999908447266,-0.01900005340576172,99.85682678222656
5,TO,csv,10,1000,13.196000099182129,13.270999908447266,-0.07499980926513672,99.43486022949219
6,TO,csv,10,1000,13.20300006866455,13.270999908447266,-0.06799983978271484,99.48760986328125
0,FROM,csv,10,10000,17.642501831054688,17.642501831054688,0.0,100.0
1,FROM,csv,10,10000,17.685001373291016,17.642501831054688,0.042499542236328125,100.24089813232422
2,FROM,csv,10,10000,17.63050079345703,17.642501831054688,-0.01200103759765625,99.93197631835938
3,FROM,csv,10,10000,17.729000091552734,17.642501831054688,0.08649826049804688,100.49028015136719
4,FROM,csv,10,10000,17.7185001373291,17.642501831054688,0.07599830627441406,100.4307632446289
5,FROM,csv,10,10000,17.730499267578125,17.642501831054688,0.0879974365234375,100.49878692626953
6,FROM,csv,10,10000,17.73900032043457,17.642501831054688,0.09649848937988281,100.54696655273438
0,TO,csv,10,10000,15.422500610351562,15.422500610351562,0.0,100.0
1,TO,csv,10,10000,15.36299991607666,15.422500610351562,-0.059500694274902344,99.61419677734375
2,TO,csv,10,10000,15.46299934387207,15.422500610351562,0.04049873352050781,100.2625961303711
3,TO,csv,10,10000,15.462499618530273,15.422500610351562,0.03999900817871094,100.25935363769531
4,TO,csv,10,10000,15.517000198364258,15.422500610351562,0.09449958801269531,100.61273193359375
5,TO,csv,10,10000,15.430000305175781,15.422500610351562,0.00749969482421875,100.04862213134766
6,TO,csv,10,10000,15.461999893188477,15.422500610351562,0.03949928283691406,100.25611114501953
0,FROM,csv,10,100000,37.66699981689453,37.66699981689453,0.0,100.0
1,FROM,csv,10,100000,37.577999114990234,37.66699981689453,-0.08900070190429688,99.76371765136719
2,FROM,csv,10,100000,37.95100021362305,37.66699981689453,0.2840003967285156,100.75397491455078
3,FROM,csv,10,100000,38.07400131225586,37.66699981689453,0.4070014953613281,101.08052825927734
4,FROM,csv,10,100000,37.87099838256836,37.66699981689453,0.20399856567382812,100.54158020019531
5,FROM,csv,10,100000,37.71900177001953,37.66699981689453,0.052001953125,100.13805389404297
6,FROM,csv,10,100000,37.76900100708008,37.66699981689453,0.10200119018554688,100.27079772949219
0,TO,csv,10,100000,37.93299865722656,37.93299865722656,0.0,100.0
1,TO,csv,10,100000,37.36000061035156,37.93299865722656,-0.572998046875,98.48944854736328
2,TO,csv,10,100000,37.459999084472656,37.93299865722656,-0.47299957275390625,98.75306701660156
3,TO,csv,10,100000,37.637001037597656,37.93299865722656,-0.29599761962890625,99.21968841552734
4,TO,csv,10,100000,37.59400177001953,37.93299865722656,-0.33899688720703125,99.10633087158203
5,TO,csv,10,100000,37.67599868774414,37.93299865722656,-0.2569999694824219,99.32249450683594
6,TO,csv,10,100000,37.770999908447266,37.93299865722656,-0.16199874877929688,99.57292938232422
0,FROM,csv,10,1000000,237.24899291992188,237.24899291992188,0.0,100.0
1,FROM,csv,10,1000000,237.14700317382812,237.24899291992188,-0.10198974609375,99.95701599121094
2,FROM,csv,10,1000000,238.99000549316406,237.24899291992188,1.7410125732421875,100.73382568359375
3,FROM,csv,10,1000000,240.4810028076172,237.24899291992188,3.2320098876953125,101.36228942871094
4,FROM,csv,10,1000000,239.18499755859375,237.24899291992188,1.936004638671875,100.81602478027344
5,FROM,csv,10,1000000,237.49600219726562,237.24899291992188,0.24700927734375,100.10411834716797
6,FROM,csv,10,1000000,237.4969940185547,237.24899291992188,0.2480010986328125,100.10453796386719
0,TO,csv,10,1000000,255.99099731445312,255.99099731445312,0.0,100.0
1,TO,csv,10,1000000,253.2689971923828,255.99099731445312,-2.7220001220703125,98.93668365478516
2,TO,csv,10,1000000,253.27200317382812,255.99099731445312,-2.718994140625,98.93785858154297
3,TO,csv,10,1000000,253.5590057373047,255.99099731445312,-2.4319915771484375,99.04996490478516
4,TO,csv,10,1000000,254.4949951171875,255.99099731445312,-1.496002197265625,99.41560363769531
5,TO,csv,10,1000000,255.46200561523438,255.99099731445312,-0.52899169921875,99.7933578491211
6,TO,csv,10,1000000,255.59800720214844,255.99099731445312,-0.3929901123046875,99.84648132324219
0,FROM,csv,100,10,13.300999641418457,13.300999641418457,0.0,100.0
1,FROM,csv,100,10,13.414999961853027,13.300999641418457,0.11400032043457031,100.8570785522461
2,FROM,csv,100,10,13.354000091552734,13.300999641418457,0.053000450134277344,100.39846801757812
3,FROM,csv,100,10,13.336999893188477,13.300999641418457,0.03600025177001953,100.2706527709961
4,FROM,csv,100,10,13.401000022888184,13.300999641418457,0.10000038146972656,100.7518310546875
5,FROM,csv,100,10,13.343999862670898,13.300999641418457,0.043000221252441406,100.32328033447266
6,FROM,csv,100,10,13.359000205993652,13.300999641418457,0.05800056457519531,100.43606567382812
0,TO,csv,100,10,12.99899959564209,12.99899959564209,0.0,100.0
1,TO,csv,100,10,13.092000007629395,12.99899959564209,0.09300041198730469,100.71544647216797
2,TO,csv,100,10,13.036999702453613,12.99899959564209,0.03800010681152344,100.2923355102539
3,TO,csv,100,10,13.119000434875488,12.99899959564209,0.12000083923339844,100.92315673828125
4,TO,csv,100,10,13.034000396728516,12.99899959564209,0.03500080108642578,100.26925659179688
5,TO,csv,100,10,13.057999610900879,12.99899959564209,0.05900001525878906,100.4538803100586
6,TO,csv,100,10,13.211000442504883,12.99899959564209,0.21200084686279297,101.63090515136719
0,FROM,csv,100,100,13.708999633789062,13.708999633789062,0.0,100.0
1,FROM,csv,100,100,13.586999893188477,13.708999633789062,-0.12199974060058594,99.11006927490234
2,FROM,csv,100,100,13.666999816894531,13.708999633789062,-0.04199981689453125,99.69363403320312
3,FROM,csv,100,100,13.817000389099121,13.708999633789062,0.1080007553100586,100.78780364990234
4,FROM,csv,100,100,13.732999801635742,13.708999633789062,0.024000167846679688,100.1750717163086
5,FROM,csv,100,100,13.609000205993652,13.708999633789062,-0.09999942779541016,99.27056121826172
6,FROM,csv,100,100,13.701000213623047,13.708999633789062,-0.007999420166015625,99.941650390625
0,TO,csv,100,100,13.128000259399414,13.128000259399414,0.0,100.0
1,TO,csv,100,100,13.20300006866455,13.128000259399414,0.07499980926513672,100.57129669189453
2,TO,csv,100,100,13.159000396728516,13.128000259399414,0.031000137329101562,100.23614501953125
3,TO,csv,100,100,13.208000183105469,13.128000259399414,0.07999992370605469,100.60938262939453
4,TO,csv,100,100,13.1850004196167,13.128000259399414,0.057000160217285156,100.4341812133789
5,TO,csv,100,100,13.21500015258789,13.128000259399414,0.08699989318847656,100.66270446777344
6,TO,csv,100,100,13.25,13.128000259399414,0.12199974060058594,100.92930603027344
0,FROM,csv,100,1000,15.803999900817871,15.803999900817871,0.0,100.0
1,FROM,csv,100,1000,15.850000381469727,15.803999900817871,0.04600048065185547,100.29107666015625
2,FROM,csv,100,1000,15.781000137329102,15.803999900817871,-0.02299976348876953,99.8544692993164
3,FROM,csv,100,1000,15.892000198364258,15.803999900817871,0.08800029754638672,100.55682373046875
4,FROM,csv,100,1000,15.932000160217285,15.803999900817871,0.12800025939941406,100.80992126464844
5,FROM,csv,100,1000,15.831999778747559,15.803999900817871,0.0279998779296875,100.17716979980469
6,FROM,csv,100,1000,15.83899974822998,15.803999900817871,0.034999847412109375,100.22146606445312
0,TO,csv,100,1000,14.781999588012695,14.781999588012695,0.0,100.0
1,TO,csv,100,1000,14.732000350952148,14.781999588012695,-0.049999237060546875,99.66175842285156
2,TO,csv,100,1000,14.678999900817871,14.781999588012695,-0.10299968719482422,99.30320739746094
3,TO,csv,100,1000,14.871999740600586,14.781999588012695,0.09000015258789062,100.60884857177734
4,TO,csv,100,1000,14.798999786376953,14.781999588012695,0.017000198364257812,100.11499786376953
5,TO,csv,100,1000,14.762999534606934,14.781999588012695,-0.01900005340576172,99.8714599609375
6,TO,csv,100,1000,14.930999755859375,14.781999588012695,0.1490001678466797,101.00798797607422
0,FROM,csv,100,10000,33.61650085449219,33.61650085449219,0.0,100.0
1,FROM,csv,100,10000,33.580501556396484,33.61650085449219,-0.035999298095703125,99.89291381835938
2,FROM,csv,100,10000,33.77400207519531,33.61650085449219,0.157501220703125,100.4685287475586
3,FROM,csv,100,10000,33.822998046875,33.61650085449219,0.2064971923828125,100.61427307128906
4,FROM,csv,100,10000,33.85300064086914,33.61650085449219,0.23649978637695312,100.70352172851562
5,FROM,csv,100,10000,33.784000396728516,33.61650085449219,0.16749954223632812,100.4982681274414
6,FROM,csv,100,10000,33.836997985839844,33.61650085449219,0.22049713134765625,100.65592193603516
0,TO,csv,100,10000,30.820999145507812,30.820999145507812,0.0,100.0
1,TO,csv,100,10000,30.477500915527344,30.820999145507812,-0.34349822998046875,98.88550567626953
2,TO,csv,100,10000,30.45600128173828,30.820999145507812,-0.36499786376953125,98.81575012207031
3,TO,csv,100,10000,30.535999298095703,30.820999145507812,-0.2849998474121094,99.07530212402344
4,TO,csv,100,10000,30.61600112915039,30.820999145507812,-0.20499801635742188,99.33487701416016
5,TO,csv,100,10000,30.792499542236328,30.820999145507812,-0.028499603271484375,99.90753173828125
6,TO,csv,100,10000,30.78350067138672,30.820999145507812,-0.03749847412109375,99.87833404541016
0,FROM,csv,100,100000,209.468994140625,209.468994140625,0.0,100.0
1,FROM,csv,100,100000,210.0570068359375,209.468994140625,0.5880126953125,100.28071594238281
2,FROM,csv,100,100000,211.92100524902344,209.468994140625,2.4520111083984375,101.17058563232422
3,FROM,csv,100,100000,210.48500061035156,209.468994140625,1.0160064697265625,100.48503875732422
4,FROM,csv,100,100000,212.94700622558594,209.468994140625,3.4780120849609375,101.66039276123047
5,FROM,csv,100,100000,210.3489990234375,209.468994140625,0.8800048828125,100.42012023925781
6,FROM,csv,100,100000,210.302001953125,209.468994140625,0.8330078125,100.39766693115234
0,TO,csv,100,100000,189.66299438476562,189.66299438476562,0.0,100.0
1,TO,csv,100,100000,186.18299865722656,189.66299438476562,-3.4799957275390625,98.16516876220703
2,TO,csv,100,100000,186.35699462890625,189.66299438476562,-3.305999755859375,98.25691223144531
3,TO,csv,100,100000,186.51499938964844,189.66299438476562,-3.1479949951171875,98.34021759033203
4,TO,csv,100,100000,186.51300048828125,189.66299438476562,-3.149993896484375,98.33916473388672
5,TO,csv,100,100000,189.51600646972656,189.66299438476562,-0.1469879150390625,99.92250061035156
6,TO,csv,100,100000,190.70399475097656,189.66299438476562,1.0410003662109375,100.54886627197266
0,FROM,csv,100,1000000,1977.6519775390625,1977.6519775390625,0.0,100.0
1,FROM,csv,100,1000000,1973.8089599609375,1977.6519775390625,-3.843017578125,99.80567932128906
2,FROM,csv,100,1000000,1987.6180419921875,1977.6519775390625,9.966064453125,100.50393676757812
3,FROM,csv,100,1000000,1973.571044921875,1977.6519775390625,-4.0809326171875,99.79364776611328
4,FROM,csv,100,1000000,1998.488037109375,1977.6519775390625,20.8360595703125,101.05357360839844
5,FROM,csv,100,1000000,1973.7679443359375,1977.6519775390625,-3.884033203125,99.80360412597656
6,FROM,csv,100,1000000,1972.9610595703125,1977.6519775390625,-4.69091796875,99.76280212402344
0,TO,csv,100,1000000,1758.8270263671875,1758.8270263671875,0.0,100.0
1,TO,csv,100,1000000,1727.3919677734375,1758.8270263671875,-31.43505859375,98.21272277832031
2,TO,csv,100,1000000,1727.1650390625,1758.8270263671875,-31.6619873046875,98.1998291015625
3,TO,csv,100,1000000,1726.8060302734375,1758.8270263671875,-32.02099609375,98.17941284179688
4,TO,csv,100,1000000,1728.1619873046875,1758.8270263671875,-30.6650390625,98.25650787353516
5,TO,csv,100,1000000,1758.2559814453125,1758.8270263671875,-0.571044921875,99.96753692626953
6,TO,csv,100,1000000,1767.5570068359375,1758.8270263671875,8.72998046875,100.49635314941406
0,FROM,text,1,10,14.460000038146973,14.460000038146973,0.0,100.0
1,FROM,text,1,10,14.130999565124512,14.460000038146973,-0.32900047302246094,97.7247543334961
2,FROM,text,1,10,14.14900016784668,14.460000038146973,-0.31099987030029297,97.84923553466797
3,FROM,text,1,10,14.229000091552734,14.460000038146973,-0.23099994659423828,98.4024887084961
4,FROM,text,1,10,14.345999717712402,14.460000038146973,-0.11400032043457031,99.21161651611328
5,FROM,text,1,10,14.1850004196167,14.460000038146973,-0.27499961853027344,98.09820556640625
6,FROM,text,1,10,13.01099967956543,14.460000038146973,-1.449000358581543,89.979248046875
0,TO,text,1,10,14.378000259399414,14.378000259399414,0.0,100.0
1,TO,text,1,10,13.895999908447266,14.378000259399414,-0.48200035095214844,96.64765930175781
2,TO,text,1,10,13.970999717712402,14.378000259399414,-0.4070005416870117,97.16928100585938
3,TO,text,1,10,14.010000228881836,14.378000259399414,-0.3680000305175781,97.44053649902344
4,TO,text,1,10,14.067000389099121,14.378000259399414,-0.31099987030029297,97.83697509765625
5,TO,text,1,10,14.13599967956543,14.378000259399414,-0.24200057983398438,98.31686401367188
6,TO,text,1,10,13.166000366210938,14.378000259399414,-1.2119998931884766,91.5704574584961
0,FROM,text,1,100,13.9350004196167,13.9350004196167,0.0,100.0
1,FROM,text,1,100,14.418999671936035,13.9350004196167,0.48399925231933594,103.47325897216797
2,FROM,text,1,100,14.520000457763672,13.9350004196167,0.5850000381469727,104.19805908203125
3,FROM,text,1,100,14.038000106811523,13.9350004196167,0.10299968719482422,100.73914337158203
4,FROM,text,1,100,14.411999702453613,13.9350004196167,0.47699928283691406,103.42303466796875
5,FROM,text,1,100,14.291000366210938,13.9350004196167,0.3559999465942383,102.55471801757812
6,FROM,text,1,100,13.935999870300293,13.9350004196167,0.00099945068359375,100.0071792602539
0,TO,text,1,100,14.03600025177002,14.03600025177002,0.0,100.0
1,TO,text,1,100,13.930999755859375,14.03600025177002,-0.10500049591064453,99.25192260742188
2,TO,text,1,100,13.965999603271484,14.03600025177002,-0.07000064849853516,99.50127410888672
3,TO,text,1,100,14.184000015258789,14.03600025177002,0.14799976348876953,101.05442810058594
4,TO,text,1,100,13.918000221252441,14.03600025177002,-0.11800003051757812,99.15930938720703
5,TO,text,1,100,14.060999870300293,14.03600025177002,0.024999618530273438,100.17810821533203
6,TO,text,1,100,13.795000076293945,14.03600025177002,-0.24100017547607422,98.28298950195312
0,FROM,text,1,1000,16.121000289916992,16.121000289916992,0.0,100.0
1,FROM,text,1,1000,15.880999565124512,16.121000289916992,-0.24000072479248047,98.5112533569336
2,FROM,text,1,1000,15.857999801635742,16.121000289916992,-0.26300048828125,98.36858367919922
3,FROM,text,1,1000,15.354999542236328,16.121000289916992,-0.7660007476806641,95.24842834472656
4,FROM,text,1,1000,16.49799919128418,16.121000289916992,0.3769989013671875,102.33855438232422
5,FROM,text,1,1000,15.72599983215332,16.121000289916992,-0.3950004577636719,97.5497817993164
6,FROM,text,1,1000,16.16699981689453,16.121000289916992,0.04599952697753906,100.28533935546875
0,TO,text,1,1000,13.847000122070312,13.847000122070312,0.0,100.0
1,TO,text,1,1000,13.706999778747559,13.847000122070312,-0.1400003433227539,98.98895263671875
2,TO,text,1,1000,13.696999549865723,13.847000122070312,-0.15000057220458984,98.9167251586914
3,TO,text,1,1000,12.935999870300293,13.847000122070312,-0.9110002517700195,93.42095947265625
4,TO,text,1,1000,14.041000366210938,13.847000122070312,0.194000244140625,101.40103149414062
5,TO,text,1,1000,13.871000289916992,13.847000122070312,0.024000167846679688,100.1733169555664
6,TO,text,1,1000,13.947999954223633,13.847000122070312,0.10099983215332031,100.7293930053711
0,FROM,text,1,10000,15.651000022888184,15.651000022888184,0.0,100.0
1,FROM,text,1,10000,15.725000381469727,15.651000022888184,0.07400035858154297,100.47281646728516
2,FROM,text,1,10000,15.711999893188477,15.651000022888184,0.06099987030029297,100.38975524902344
3,FROM,text,1,10000,16.532501220703125,15.651000022888184,0.8815011978149414,105.63223266601562
4,FROM,text,1,10000,15.845000267028809,15.651000022888184,0.194000244140625,101.23954010009766
5,FROM,text,1,10000,15.738499641418457,15.651000022888184,0.08749961853027344,100.55906677246094
6,FROM,text,1,10000,16.97800064086914,15.651000022888184,1.327000617980957,108.47869873046875
0,TO,text,1,10000,13.978500366210938,13.978500366210938,0.0,100.0
1,TO,text,1,10000,13.427000045776367,13.978500366210938,-0.5515003204345703,96.05465698242188
2,TO,text,1,10000,13.529999732971191,13.978500366210938,-0.4485006332397461,96.79149627685547
3,TO,text,1,10000,14.212499618530273,13.978500366210938,0.23399925231933594,101.67399597167969
4,TO,text,1,10000,13.908499717712402,13.978500366210938,-0.07000064849853516,99.49922180175781
5,TO,text,1,10000,13.755499839782715,13.978500366210938,-0.22300052642822266,98.4046859741211
6,TO,text,1,10000,14.724000930786133,13.978500366210938,0.7455005645751953,105.33319854736328
0,FROM,text,1,100000,22.114999771118164,22.114999771118164,0.0,100.0
1,FROM,text,1,100000,22.19700050354004,22.114999771118164,0.082000732421875,100.37078857421875
2,FROM,text,1,100000,22.375999450683594,22.114999771118164,0.2609996795654297,101.1801986694336
3,FROM,text,1,100000,22.63800048828125,22.114999771118164,0.5230007171630859,102.36490631103516
4,FROM,text,1,100000,21.56999969482422,22.114999771118164,-0.5450000762939453,97.53561401367188
5,FROM,text,1,100000,22.392000198364258,22.114999771118164,0.27700042724609375,101.2525405883789
6,FROM,text,1,100000,23.030000686645508,22.114999771118164,0.9150009155273438,104.13746643066406
0,TO,text,1,100000,20.763999938964844,20.763999938964844,0.0,100.0
1,TO,text,1,100000,22.958999633789062,20.763999938964844,2.1949996948242188,110.57118225097656
2,TO,text,1,100000,21.680999755859375,20.763999938964844,0.9169998168945312,104.41629791259766
3,TO,text,1,100000,21.950000762939453,20.763999938964844,1.1860008239746094,105.7118148803711
4,TO,text,1,100000,20.898000717163086,20.763999938964844,0.1340007781982422,100.64535522460938
5,TO,text,1,100000,21.732999801635742,20.763999938964844,0.9689998626708984,104.66673278808594
6,TO,text,1,100000,22.06399917602539,20.763999938964844,1.2999992370605469,106.26083374023438
0,FROM,text,1,1000000,77.5719985961914,77.5719985961914,0.0,100.0
1,FROM,text,1,1000000,77.64800262451172,77.5719985961914,0.0760040283203125,100.09797668457031
2,FROM,text,1,1000000,78.99400329589844,77.5719985961914,1.4220046997070312,101.83313751220703
3,FROM,text,1,1000000,79.81400299072266,77.5719985961914,2.24200439453125,102.89022827148438
4,FROM,text,1,1000000,75.83999633789062,77.5719985961914,-1.7320022583007812,97.7672348022461
5,FROM,text,1,1000000,78.41200256347656,77.5719985961914,0.8400039672851562,101.08287048339844
6,FROM,text,1,1000000,76.58599853515625,77.5719985961914,-0.9860000610351562,98.72892761230469
0,TO,text,1,1000000,93.62699890136719,93.62699890136719,0.0,100.0
1,TO,text,1,1000000,93.34700012207031,93.62699890136719,-0.279998779296875,99.70094299316406
2,TO,text,1,1000000,93.29399871826172,93.62699890136719,-0.33300018310546875,99.64433288574219
3,TO,text,1,1000000,93.28600311279297,93.62699890136719,-0.34099578857421875,99.63578796386719
4,TO,text,1,1000000,91.98100280761719,93.62699890136719,-1.64599609375,98.2419662475586
5,TO,text,1,1000000,93.02200317382812,93.62699890136719,-0.6049957275390625,99.35382843017578
6,TO,text,1,1000000,91.12000274658203,93.62699890136719,-2.5069961547851562,97.32235717773438
0,FROM,text,10,10,14.369999885559082,14.369999885559082,0.0,100.0
1,FROM,text,10,10,14.302000045776367,14.369999885559082,-0.06799983978271484,99.52679443359375
2,FROM,text,10,10,14.246999740600586,14.369999885559082,-0.1230001449584961,99.14405059814453
3,FROM,text,10,10,14.222999572753906,14.369999885559082,-0.14700031280517578,98.97703552246094
4,FROM,text,10,10,13.239999771118164,14.369999885559082,-1.130000114440918,92.13639831542969
5,FROM,text,10,10,14.170000076293945,14.369999885559082,-0.19999980926513672,98.60821533203125
6,FROM,text,10,10,12.944999694824219,14.369999885559082,-1.4250001907348633,90.08350372314453
0,TO,text,10,10,13.916000366210938,13.916000366210938,0.0,100.0
1,TO,text,10,10,14.03499984741211,13.916000366210938,0.11899948120117188,100.8551254272461
2,TO,text,10,10,14.111000061035156,13.916000366210938,0.19499969482421875,101.40126037597656
3,TO,text,10,10,13.871999740600586,13.916000366210938,-0.04400062561035156,99.6838150024414
4,TO,text,10,10,12.784000396728516,13.916000366210938,-1.1319999694824219,91.865478515625
5,TO,text,10,10,13.901000022888184,13.916000366210938,-0.015000343322753906,99.89220428466797
6,TO,text,10,10,12.640999794006348,13.916000366210938,-1.2750005722045898,90.83787536621094
0,FROM,text,10,100,14.477999687194824,14.477999687194824,0.0,100.0
1,FROM,text,10,100,13.258000373840332,14.477999687194824,-1.2199993133544922,91.57342529296875
2,FROM,text,10,100,13.270000457763672,14.477999687194824,-1.2079992294311523,91.65631103515625
3,FROM,text,10,100,14.284000396728516,14.477999687194824,-0.1939992904663086,98.66004180908203
4,FROM,text,10,100,13.39799976348877,14.477999687194824,-1.0799999237060547,92.5404052734375
5,FROM,text,10,100,14.069999694824219,14.477999687194824,-0.40799999237060547,97.18193054199219
6,FROM,text,10,100,13.21500015258789,14.477999687194824,-1.2629995346069336,91.27642822265625
0,TO,text,10,100,13.991999626159668,13.991999626159668,0.0,100.0
1,TO,text,10,100,14.07800006866455,13.991999626159668,0.08600044250488281,100.61463928222656
2,TO,text,10,100,14.003999710083008,13.991999626159668,0.012000083923339844,100.08576202392578
3,TO,text,10,100,14.097000122070312,13.991999626159668,0.10500049591064453,100.75043487548828
4,TO,text,10,100,13.194999694824219,13.991999626159668,-0.7969999313354492,94.30388641357422
5,TO,text,10,100,13.920000076293945,13.991999626159668,-0.07199954986572266,99.48542022705078
6,TO,text,10,100,12.70199966430664,13.991999626159668,-1.2899999618530273,90.78044891357422
0,FROM,text,10,1000,15.369999885559082,15.369999885559082,0.0,100.0
1,FROM,text,10,1000,15.954999923706055,15.369999885559082,0.5850000381469727,103.80611419677734
2,FROM,text,10,1000,15.597000122070312,15.369999885559082,0.22700023651123047,101.4769058227539
3,FROM,text,10,1000,15.531000137329102,15.369999885559082,0.16100025177001953,101.04749298095703
4,FROM,text,10,1000,15.637999534606934,15.369999885559082,0.26799964904785156,101.74365234375
5,FROM,text,10,1000,15.541000366210938,15.369999885559082,0.17100048065185547,101.11255645751953
6,FROM,text,10,1000,15.305999755859375,15.369999885559082,-0.06400012969970703,99.58360290527344
0,TO,text,10,1000,12.989999771118164,12.989999771118164,0.0,100.0
1,TO,text,10,1000,13.404999732971191,12.989999771118164,0.41499996185302734,103.19476318359375
2,TO,text,10,1000,13.182000160217285,12.989999771118164,0.1920003890991211,101.47806549072266
3,TO,text,10,1000,12.902000427246094,12.989999771118164,-0.08799934387207031,99.32256317138672
4,TO,text,10,1000,13.16100025177002,12.989999771118164,0.17100048065185547,101.31640625
5,TO,text,10,1000,13.145999908447266,12.989999771118164,0.15600013732910156,101.200927734375
6,TO,text,10,1000,13.199999809265137,12.989999771118164,0.21000003814697266,101.61663055419922
0,FROM,text,10,10000,17.19649887084961,17.19649887084961,0.0,100.0
1,FROM,text,10,10000,17.083999633789062,17.19649887084961,-0.11249923706054688,99.3458023071289
2,FROM,text,10,10000,17.34000015258789,17.19649887084961,0.14350128173828125,100.83448028564453
3,FROM,text,10,10000,17.152999877929688,17.19649887084961,-0.043498992919921875,99.7470474243164
4,FROM,text,10,10000,17.230499267578125,17.19649887084961,0.034000396728515625,100.19772338867188
5,FROM,text,10,10000,17.052499771118164,17.19649887084961,-0.1439990997314453,99.16262817382812
6,FROM,text,10,10000,17.255001068115234,17.19649887084961,0.058502197265625,100.34020233154297
0,TO,text,10,10000,15.267499923706055,15.267499923706055,0.0,100.0
1,TO,text,10,10000,14.845000267028809,15.267499923706055,-0.4224996566772461,97.2326889038086
2,TO,text,10,10000,15.045499801635742,15.267499923706055,-0.2220001220703125,98.54592895507812
3,TO,text,10,10000,14.986000061035156,15.267499923706055,-0.28149986267089844,98.15621185302734
4,TO,text,10,10000,15.241000175476074,15.267499923706055,-0.02649974822998047,99.82643127441406
5,TO,text,10,10000,14.935999870300293,15.267499923706055,-0.3315000534057617,97.82872009277344
6,TO,text,10,10000,14.92449951171875,15.267499923706055,-0.3430004119873047,97.7533950805664
0,FROM,text,10,100000,35.10200119018555,35.10200119018555,0.0,100.0
1,FROM,text,10,100000,34.99700164794922,35.10200119018555,-0.10499954223632812,99.70087432861328
2,FROM,text,10,100000,35.25899887084961,35.10200119018555,0.1569976806640625,100.44725799560547
3,FROM,text,10,100000,35.402000427246094,35.10200119018555,0.2999992370605469,100.85464477539062
4,FROM,text,10,100000,35.349998474121094,35.10200119018555,0.24799728393554688,100.70650482177734
5,FROM,text,10,100000,35.2239990234375,35.10200119018555,0.12199783325195312,100.3475570678711
6,FROM,text,10,100000,35.332000732421875,35.10200119018555,0.22999954223632812,100.65523529052734
0,TO,text,10,100000,34.183998107910156,34.183998107910156,0.0,100.0
1,TO,text,10,100000,33.939998626708984,34.183998107910156,-0.24399948120117188,99.28621673583984
2,TO,text,10,100000,34.027000427246094,34.183998107910156,-0.1569976806640625,99.54072570800781
3,TO,text,10,100000,34.077999114990234,34.183998107910156,-0.10599899291992188,99.6899185180664
4,TO,text,10,100000,34.409000396728516,34.183998107910156,0.22500228881835938,100.65821075439453
5,TO,text,10,100000,33.97100067138672,34.183998107910156,-0.2129974365234375,99.37690734863281
6,TO,text,10,100000,34.11800003051758,34.183998107910156,-0.06599807739257812,99.80693817138672
0,FROM,text,10,1000000,211.4929962158203,211.4929962158203,0.0,100.0
1,FROM,text,10,1000000,211.46499633789062,211.4929962158203,-0.0279998779296875,99.98676300048828
2,FROM,text,10,1000000,210.26199340820312,211.4929962158203,-1.2310028076171875,99.4179458618164
3,FROM,text,10,1000000,212.92100524902344,211.4929962158203,1.428009033203125,100.67520141601562
4,FROM,text,10,1000000,211.69500732421875,211.4929962158203,0.2020111083984375,100.09552001953125
5,FROM,text,10,1000000,213.98500061035156,211.4929962158203,2.49200439453125,101.17829132080078
6,FROM,text,10,1000000,211.91900634765625,211.4929962158203,0.4260101318359375,100.20143127441406
0,TO,text,10,1000000,220.33399963378906,220.33399963378906,0.0,100.0
1,TO,text,10,1000000,220.46499633789062,220.33399963378906,0.1309967041015625,100.0594482421875
2,TO,text,10,1000000,220.1479949951172,220.33399963378906,-0.186004638671875,99.91558074951172
3,TO,text,10,1000000,220.75,220.33399963378906,0.4160003662109375,100.18880462646484
4,TO,text,10,1000000,221.56900024414062,220.33399963378906,1.2350006103515625,100.56050872802734
5,TO,text,10,1000000,219.94000244140625,220.33399963378906,-0.3939971923828125,99.82118225097656
6,TO,text,10,1000000,221.0019989013672,220.33399963378906,0.667999267578125,100.30317687988281
0,FROM,text,100,10,13.246000289916992,13.246000289916992,0.0,100.0
1,FROM,text,100,10,13.697999954223633,13.246000289916992,0.4519996643066406,103.412353515625
2,FROM,text,100,10,13.401000022888184,13.246000289916992,0.1549997329711914,101.17015838623047
3,FROM,text,100,10,13.42300033569336,13.246000289916992,0.1770000457763672,101.33625030517578
4,FROM,text,100,10,13.538999557495117,13.246000289916992,0.292999267578125,102.21199035644531
5,FROM,text,100,10,13.791999816894531,13.246000289916992,0.5459995269775391,104.12199401855469
6,FROM,text,100,10,13.4350004196167,13.246000289916992,0.18900012969970703,101.42684936523438
0,TO,text,100,10,13.032999992370605,13.032999992370605,0.0,100.0
1,TO,text,100,10,13.210000038146973,13.032999992370605,0.1770000457763672,101.35809326171875
2,TO,text,100,10,12.916999816894531,13.032999992370605,-0.11600017547607422,99.10994720458984
3,TO,text,100,10,13.055000305175781,13.032999992370605,0.02200031280517578,100.1688003540039
4,TO,text,100,10,13.25,13.032999992370605,0.21700000762939453,101.66500854492188
5,TO,text,100,10,13.876999855041504,13.032999992370605,0.8439998626708984,106.47586822509766
6,TO,text,100,10,13.086000442504883,13.032999992370605,0.053000450134277344,100.40666198730469
0,FROM,text,100,100,13.557999610900879,13.557999610900879,0.0,100.0
1,FROM,text,100,100,13.652000427246094,13.557999610900879,0.09400081634521484,100.69332122802734
2,FROM,text,100,100,13.803999900817871,13.557999610900879,0.2460002899169922,101.81442260742188
3,FROM,text,100,100,13.76099967956543,13.557999610900879,0.20300006866455078,101.49726867675781
4,FROM,text,100,100,13.717000007629395,13.557999610900879,0.15900039672851562,101.17274475097656
5,FROM,text,100,100,13.600000381469727,13.557999610900879,0.042000770568847656,100.3097915649414
6,FROM,text,100,100,13.715999603271484,13.557999610900879,0.15799999237060547,101.16536712646484
0,TO,text,100,100,13.161999702453613,13.161999702453613,0.0,100.0
1,TO,text,100,100,13.711000442504883,13.161999702453613,0.5490007400512695,104.17111206054688
2,TO,text,100,100,13.446999549865723,13.161999702453613,0.2849998474121094,102.16531372070312
3,TO,text,100,100,13.29699993133545,13.161999702453613,0.13500022888183594,101.02568054199219
4,TO,text,100,100,13.180999755859375,13.161999702453613,0.01900005340576172,100.14434814453125
5,TO,text,100,100,13.079000473022461,13.161999702453613,-0.08299922943115234,99.36940002441406
6,TO,text,100,100,13.26200008392334,13.161999702453613,0.10000038146972656,100.759765625
0,FROM,text,100,1000,15.505000114440918,15.505000114440918,0.0,100.0
1,FROM,text,100,1000,15.432000160217285,15.505000114440918,-0.07299995422363281,99.52918243408203
2,FROM,text,100,1000,15.567000389099121,15.505000114440918,0.062000274658203125,100.39987182617188
3,FROM,text,100,1000,15.527999877929688,15.505000114440918,0.02299976348876953,100.14833068847656
4,FROM,text,100,1000,15.57699966430664,15.505000114440918,0.07199954986572266,100.46437072753906
5,FROM,text,100,1000,15.487000465393066,15.505000114440918,-0.017999649047851562,99.8839111328125
6,FROM,text,100,1000,15.503000259399414,15.505000114440918,-0.0019998550415039062,99.98709869384766
0,TO,text,100,1000,14.508999824523926,14.508999824523926,0.0,100.0
1,TO,text,100,1000,14.404999732971191,14.508999824523926,-0.10400009155273438,99.283203125
2,TO,text,100,1000,14.543999671936035,14.508999824523926,0.034999847412109375,100.2412338256836
3,TO,text,100,1000,14.581999778747559,14.508999824523926,0.07299995422363281,100.50313568115234
4,TO,text,100,1000,14.557999610900879,14.508999824523926,0.048999786376953125,100.33772277832031
5,TO,text,100,1000,14.519000053405762,14.508999824523926,0.010000228881835938,100.06892395019531
6,TO,text,100,1000,14.640000343322754,14.508999824523926,0.13100051879882812,100.90289306640625
0,FROM,text,100,10000,29.819000244140625,29.819000244140625,0.0,100.0
1,FROM,text,100,10000,29.845001220703125,29.819000244140625,0.0260009765625,100.08720397949219
2,FROM,text,100,10000,29.807498931884766,29.819000244140625,-0.011501312255859375,99.96143341064453
3,FROM,text,100,10000,29.894500732421875,29.819000244140625,0.07550048828125,100.25320434570312
4,FROM,text,100,10000,29.769001007080078,29.819000244140625,-0.049999237060546875,99.83232879638672
5,FROM,text,100,10000,29.81399917602539,29.819000244140625,-0.005001068115234375,99.98323059082031
6,FROM,text,100,10000,29.749000549316406,29.819000244140625,-0.06999969482421875,99.76525115966797
0,TO,text,100,10000,27.802501678466797,27.802501678466797,0.0,100.0
1,TO,text,100,10000,27.705501556396484,27.802501678466797,-0.0970001220703125,99.65110778808594
2,TO,text,100,10000,27.857500076293945,27.802501678466797,0.05499839782714844,100.19781494140625
3,TO,text,100,10000,27.802000045776367,27.802501678466797,-0.0005016326904296875,99.9981918334961
4,TO,text,100,10000,27.788999557495117,27.802501678466797,-0.013502120971679688,99.95143127441406
5,TO,text,100,10000,27.812000274658203,27.802501678466797,0.00949859619140625,100.03416442871094
6,TO,text,100,10000,27.812999725341797,27.802501678466797,0.010498046875,100.03775024414062
0,FROM,text,100,100000,171.52000427246094,171.52000427246094,0.0,100.0
1,FROM,text,100,100000,171.552001953125,171.52000427246094,0.0319976806640625,100.0186538696289
2,FROM,text,100,100000,171.0070037841797,171.52000427246094,-0.51300048828125,99.70091247558594
3,FROM,text,100,100000,171.48199462890625,171.52000427246094,-0.0380096435546875,99.97783660888672
4,FROM,text,100,100000,171.3679962158203,171.52000427246094,-0.152008056640625,99.911376953125
5,FROM,text,100,100000,171.34500122070312,171.52000427246094,-0.1750030517578125,99.8979721069336
6,FROM,text,100,100000,171.16000366210938,171.52000427246094,-0.3600006103515625,99.79011535644531
0,TO,text,100,100000,158.66200256347656,158.66200256347656,0.0,100.0
1,TO,text,100,100000,158.3730010986328,158.66200256347656,-0.28900146484375,99.8178482055664
2,TO,text,100,100000,158.29600524902344,158.66200256347656,-0.365997314453125,99.76932525634766
3,TO,text,100,100000,158.51300048828125,158.66200256347656,-0.1490020751953125,99.90608978271484
4,TO,text,100,100000,158.8800048828125,158.66200256347656,0.2180023193359375,100.13739776611328
5,TO,text,100,100000,158.6199951171875,158.66200256347656,-0.0420074462890625,99.97352600097656
6,TO,text,100,100000,159.67100524902344,158.66200256347656,1.009002685546875,100.63594818115234
0,FROM,text,100,1000000,1580.89404296875,1580.89404296875,0.0,100.0
1,FROM,text,100,1000000,1581.5570068359375,1580.89404296875,0.6629638671875,100.04193878173828
2,FROM,text,100,1000000,1579.0069580078125,1580.89404296875,-1.8870849609375,99.88063049316406
3,FROM,text,100,1000000,1579.5489501953125,1580.89404296875,-1.3450927734375,99.9149169921875
4,FROM,text,100,1000000,1580.2149658203125,1580.89404296875,-0.6790771484375,99.95704650878906
5,FROM,text,100,1000000,1580.240966796875,1580.89404296875,-0.653076171875,99.95868682861328
6,FROM,text,100,1000000,1580.0340576171875,1580.89404296875,-0.8599853515625,99.94560241699219
0,TO,text,100,1000000,1451.1290283203125,1451.1290283203125,0.0,100.0
1,TO,text,100,1000000,1449.10498046875,1451.1290283203125,-2.0240478515625,99.86051940917969
2,TO,text,100,1000000,1449.3900146484375,1451.1290283203125,-1.739013671875,99.88015747070312
3,TO,text,100,1000000,1450.0670166015625,1451.1290283203125,-1.06201171875,99.92681884765625
4,TO,text,100,1000000,1452.4339599609375,1451.1290283203125,1.304931640625,100.08992004394531
5,TO,text,100,1000000,1450.009033203125,1451.1290283203125,-1.1199951171875,99.92282104492188
6,TO,text,100,1000000,1467.8699951171875,1451.1290283203125,16.740966796875,101.15364837646484
version,type,format,n_columns,n_rows,runtime,base_runtime,diff_runtime,diff_percentage
0,FROM,binary,1,10,13.23900032043457,13.23900032043457,0.0,100.0
1,FROM,binary,1,10,13.222999572753906,13.23900032043457,-0.016000747680664062,99.87914276123047
2,FROM,binary,1,10,13.25100040435791,13.23900032043457,0.012000083923339844,100.09064483642578
3,FROM,binary,1,10,13.300000190734863,13.23900032043457,0.06099987030029297,100.46075439453125
4,FROM,binary,1,10,13.26200008392334,13.23900032043457,0.02299976348876953,100.17372131347656
5,FROM,binary,1,10,13.263999938964844,13.23900032043457,0.024999618530273438,100.18882751464844
6,FROM,binary,1,10,13.178000450134277,13.23900032043457,-0.06099987030029297,99.53923797607422
0,TO,binary,1,10,13.100000381469727,13.100000381469727,0.0,100.0
1,TO,binary,1,10,13.012999534606934,13.100000381469727,-0.08700084686279297,99.33587646484375
2,TO,binary,1,10,12.939000129699707,13.100000381469727,-0.16100025177001953,98.77098846435547
3,TO,binary,1,10,12.95199966430664,13.100000381469727,-0.14800071716308594,98.87022399902344
4,TO,binary,1,10,12.97700023651123,13.100000381469727,-0.1230001449584961,99.06106567382812
5,TO,binary,1,10,12.968999862670898,13.100000381469727,-0.13100051879882812,98.99999237060547
6,TO,binary,1,10,13.005999565124512,13.100000381469727,-0.09400081634521484,99.28244018554688
0,FROM,binary,1,100,13.451000213623047,13.451000213623047,0.0,100.0
1,FROM,binary,1,100,13.262999534606934,13.451000213623047,-0.18800067901611328,98.60233306884766
2,FROM,binary,1,100,13.404000282287598,13.451000213623047,-0.04699993133544922,99.65058898925781
3,FROM,binary,1,100,13.390999794006348,13.451000213623047,-0.06000041961669922,99.5539321899414
4,FROM,binary,1,100,13.317999839782715,13.451000213623047,-0.13300037384033203,99.01122283935547
5,FROM,binary,1,100,13.333999633789062,13.451000213623047,-0.11700057983398438,99.13017272949219
6,FROM,binary,1,100,13.355999946594238,13.451000213623047,-0.0950002670288086,99.29373168945312
0,TO,binary,1,100,13.074000358581543,13.074000358581543,0.0,100.0
1,TO,binary,1,100,12.954999923706055,13.074000358581543,-0.11900043487548828,99.08979797363281
2,TO,binary,1,100,12.944000244140625,13.074000358581543,-0.13000011444091797,99.00566101074219
3,TO,binary,1,100,13.020000457763672,13.074000358581543,-0.053999900817871094,99.58696746826172
4,TO,binary,1,100,12.866000175476074,13.074000358581543,-0.20800018310546875,98.4090576171875
5,TO,binary,1,100,12.92199993133545,13.074000358581543,-0.15200042724609375,98.8373794555664
6,TO,binary,1,100,12.96399974822998,13.074000358581543,-0.1100006103515625,99.15863037109375
0,FROM,binary,1,1000,15.397000312805176,15.397000312805176,0.0,100.0
1,FROM,binary,1,1000,15.34000015258789,15.397000312805176,-0.057000160217285156,99.62979888916016
2,FROM,binary,1,1000,15.305999755859375,15.397000312805176,-0.09100055694580078,99.40897369384766
3,FROM,binary,1,1000,15.406000137329102,15.397000312805176,0.008999824523925781,100.0584487915039
4,FROM,binary,1,1000,15.300000190734863,15.397000312805176,-0.0970001220703125,99.37001037597656
5,FROM,binary,1,1000,15.473999977111816,15.397000312805176,0.07699966430664062,100.50009155273438
6,FROM,binary,1,1000,15.409000396728516,15.397000312805176,0.012000083923339844,100.07794189453125
0,TO,binary,1,1000,13.109999656677246,13.109999656677246,0.0,100.0
1,TO,binary,1,1000,13.001999855041504,13.109999656677246,-0.10799980163574219,99.17620086669922
2,TO,binary,1,1000,13.152999877929688,13.109999656677246,0.043000221252441406,100.32799530029297
3,TO,binary,1,1000,13.13599967956543,13.109999656677246,0.026000022888183594,100.19831848144531
4,TO,binary,1,1000,13.043999671936035,13.109999656677246,-0.06599998474121094,99.49656677246094
5,TO,binary,1,1000,13.076000213623047,13.109999656677246,-0.03399944305419922,99.74066162109375
6,TO,binary,1,1000,13.062000274658203,13.109999656677246,-0.04799938201904297,99.63387298583984
0,FROM,binary,1,10000,15.761500358581543,15.761500358581543,0.0,100.0
1,FROM,binary,1,10000,15.905500411987305,15.761500358581543,0.14400005340576172,100.91361999511719
2,FROM,binary,1,10000,15.802499771118164,15.761500358581543,0.040999412536621094,100.26012420654297
3,FROM,binary,1,10000,15.864500045776367,15.761500358581543,0.10299968719482422,100.65349578857422
4,FROM,binary,1,10000,15.761499404907227,15.761500358581543,-9.5367431640625e-07,99.99999237060547
5,FROM,binary,1,10000,15.748499870300293,15.761500358581543,-0.01300048828125,99.91751861572266
6,FROM,binary,1,10000,15.800000190734863,15.761500358581543,0.03849983215332031,100.2442626953125
0,TO,binary,1,10000,13.827499389648438,13.827499389648438,0.0,100.0
1,TO,binary,1,10000,13.84000015258789,13.827499389648438,0.012500762939453125,100.09040832519531
2,TO,binary,1,10000,13.854499816894531,13.827499389648438,0.02700042724609375,100.19526672363281
3,TO,binary,1,10000,13.95199966430664,13.827499389648438,0.12450027465820312,100.90037536621094
4,TO,binary,1,10000,13.901500701904297,13.827499389648438,0.07400131225585938,100.5351791381836
5,TO,binary,1,10000,13.909000396728516,13.827499389648438,0.08150100708007812,100.58941650390625
6,TO,binary,1,10000,13.891000747680664,13.827499389648438,0.06350135803222656,100.45924377441406
0,FROM,binary,1,100000,20.43899917602539,20.43899917602539,0.0,100.0
1,FROM,binary,1,100000,20.417999267578125,20.43899917602539,-0.020999908447265625,99.89725494384766
2,FROM,binary,1,100000,20.291000366210938,20.43899917602539,-0.14799880981445312,99.2759017944336
3,FROM,binary,1,100000,20.31999969482422,20.43899917602539,-0.11899948120117188,99.41778564453125
4,FROM,binary,1,100000,20.41699981689453,20.43899917602539,-0.021999359130859375,99.89236450195312
5,FROM,binary,1,100000,20.22800064086914,20.43899917602539,-0.21099853515625,98.96766662597656
6,FROM,binary,1,100000,20.20199966430664,20.43899917602539,-0.23699951171875,98.8404541015625
0,TO,binary,1,100000,22.231000900268555,22.231000900268555,0.0,100.0
1,TO,binary,1,100000,22.00200080871582,22.231000900268555,-0.22900009155273438,98.96990966796875
2,TO,binary,1,100000,22.042999267578125,22.231000900268555,-0.1880016326904297,99.15432739257812
3,TO,binary,1,100000,22.038000106811523,22.231000900268555,-0.19300079345703125,99.13184356689453
4,TO,binary,1,100000,22.176000595092773,22.231000900268555,-0.05500030517578125,99.75260162353516
5,TO,binary,1,100000,21.95199966430664,22.231000900268555,-0.27900123596191406,98.74498748779297
6,TO,binary,1,100000,22.084999084472656,22.231000900268555,-0.14600181579589844,99.34325408935547
0,FROM,binary,1,1000000,64.74099731445312,64.74099731445312,0.0,100.0
1,FROM,binary,1,1000000,66.4469985961914,64.74099731445312,1.7060012817382812,102.63512420654297
2,FROM,binary,1,1000000,64.18199920654297,64.74099731445312,-0.5589981079101562,99.13655853271484
3,FROM,binary,1,1000000,65.3270034790039,64.74099731445312,0.5860061645507812,100.90515899658203
4,FROM,binary,1,1000000,64.0479965209961,64.74099731445312,-0.6930007934570312,98.92958068847656
5,FROM,binary,1,1000000,63.87300109863281,64.74099731445312,-0.8679962158203125,98.6592788696289
6,FROM,binary,1,1000000,63.67100143432617,64.74099731445312,-1.0699958801269531,98.3472671508789
0,TO,binary,1,1000000,100.33599853515625,100.33599853515625,0.0,100.0
1,TO,binary,1,1000000,100.78299713134766,100.33599853515625,0.44699859619140625,100.44549560546875
2,TO,binary,1,1000000,100.64700317382812,100.33599853515625,0.311004638671875,100.30996704101562
3,TO,binary,1,1000000,100.62200164794922,100.33599853515625,0.28600311279296875,100.28504180908203
4,TO,binary,1,1000000,101.15499877929688,100.33599853515625,0.819000244140625,100.8162612915039
5,TO,binary,1,1000000,100.35299682617188,100.33599853515625,0.016998291015625,100.01693725585938
6,TO,binary,1,1000000,101.64900207519531,100.33599853515625,1.3130035400390625,101.30860900878906
0,FROM,binary,10,10,13.142999649047852,13.142999649047852,0.0,100.0
1,FROM,binary,10,10,13.321000099182129,13.142999649047852,0.17800045013427734,101.35433959960938
2,FROM,binary,10,10,13.208000183105469,13.142999649047852,0.06500053405761719,100.49456024169922
3,FROM,binary,10,10,13.33899974822998,13.142999649047852,0.1960000991821289,101.49128723144531
4,FROM,binary,10,10,13.208000183105469,13.142999649047852,0.06500053405761719,100.49456024169922
5,FROM,binary,10,10,13.26200008392334,13.142999649047852,0.11900043487548828,100.90543365478516
6,FROM,binary,10,10,13.305999755859375,13.142999649047852,0.16300010681152344,101.24020385742188
0,TO,binary,10,10,12.883999824523926,12.883999824523926,0.0,100.0
1,TO,binary,10,10,12.968000411987305,12.883999824523926,0.0840005874633789,100.6519775390625
2,TO,binary,10,10,12.996999740600586,12.883999824523926,0.11299991607666016,100.87705993652344
3,TO,binary,10,10,12.956000328063965,12.883999824523926,0.07200050354003906,100.558837890625
4,TO,binary,10,10,12.925999641418457,12.883999824523926,0.04199981689453125,100.32598876953125
5,TO,binary,10,10,12.958999633789062,12.883999824523926,0.07499980926513672,100.58210754394531
6,TO,binary,10,10,12.906000137329102,12.883999824523926,0.02200031280517578,100.1707534790039
0,FROM,binary,10,100,13.460000038146973,13.460000038146973,0.0,100.0
1,FROM,binary,10,100,13.32800006866455,13.460000038146973,-0.13199996948242188,99.01931762695312
2,FROM,binary,10,100,13.467000007629395,13.460000038146973,0.006999969482421875,100.05200958251953
3,FROM,binary,10,100,13.350000381469727,13.460000038146973,-0.1099996566772461,99.18276977539062
4,FROM,binary,10,100,13.381999969482422,13.460000038146973,-0.07800006866455078,99.4205093383789
5,FROM,binary,10,100,13.3149995803833,13.460000038146973,-0.14500045776367188,98.9227294921875
6,FROM,binary,10,100,13.454999923706055,13.460000038146973,-0.005000114440917969,99.96285247802734
0,TO,binary,10,100,12.907999992370605,12.907999992370605,0.0,100.0
1,TO,binary,10,100,13.013999938964844,12.907999992370605,0.10599994659423828,100.82119750976562
2,TO,binary,10,100,13.031999588012695,12.907999992370605,0.12399959564208984,100.96063232421875
3,TO,binary,10,100,12.947999954223633,12.907999992370605,0.039999961853027344,100.30988311767578
4,TO,binary,10,100,12.954999923706055,12.907999992370605,0.04699993133544922,100.3641128540039
5,TO,binary,10,100,12.96399974822998,12.907999992370605,0.055999755859375,100.433837890625
6,TO,binary,10,100,13.065999984741211,12.907999992370605,0.15799999237060547,101.22405242919922
0,FROM,binary,10,1000,15.642000198364258,15.642000198364258,0.0,100.0
1,FROM,binary,10,1000,15.465999603271484,15.642000198364258,-0.17600059509277344,98.87481689453125
2,FROM,binary,10,1000,15.470999717712402,15.642000198364258,-0.17100048065185547,98.90678405761719
3,FROM,binary,10,1000,15.5,15.642000198364258,-0.1420001983642578,99.0921859741211
4,FROM,binary,10,1000,15.501999855041504,15.642000198364258,-0.1400003433227539,99.10497283935547
5,FROM,binary,10,1000,15.503999710083008,15.642000198364258,-0.13800048828125,99.11775207519531
6,FROM,binary,10,1000,15.515999794006348,15.642000198364258,-0.12600040435791016,99.19447326660156
0,TO,binary,10,1000,13.3100004196167,13.3100004196167,0.0,100.0
1,TO,binary,10,1000,13.255999565124512,13.3100004196167,-0.0540008544921875,99.59428405761719
2,TO,binary,10,1000,13.305999755859375,13.3100004196167,-0.004000663757324219,99.96994018554688
3,TO,binary,10,1000,13.381999969482422,13.3100004196167,0.07199954986572266,100.54094696044922
4,TO,binary,10,1000,13.26099967956543,13.3100004196167,-0.04900074005126953,99.63185119628906
5,TO,binary,10,1000,13.338000297546387,13.3100004196167,0.0279998779296875,100.21036529541016
6,TO,binary,10,1000,13.307999610900879,13.3100004196167,-0.0020008087158203125,99.98497009277344
0,FROM,binary,10,10000,17.182998657226562,17.182998657226562,0.0,100.0
1,FROM,binary,10,10000,17.237499237060547,17.182998657226562,0.054500579833984375,100.31717681884766
2,FROM,binary,10,10000,17.082000732421875,17.182998657226562,-0.1009979248046875,99.41222381591797
3,FROM,binary,10,10000,17.12799835205078,17.182998657226562,-0.05500030517578125,99.67991638183594
4,FROM,binary,10,10000,17.086999893188477,17.182998657226562,-0.09599876403808594,99.44131469726562
5,FROM,binary,10,10000,17.09749984741211,17.182998657226562,-0.08549880981445312,99.5024185180664
6,FROM,binary,10,10000,17.12799835205078,17.182998657226562,-0.05500030517578125,99.67991638183594
0,TO,binary,10,10000,16.127498626708984,16.127498626708984,0.0,100.0
1,TO,binary,10,10000,16.164501190185547,16.127498626708984,0.0370025634765625,100.22943878173828
2,TO,binary,10,10000,16.165000915527344,16.127498626708984,0.037502288818359375,100.2325439453125
3,TO,binary,10,10000,16.180500030517578,16.127498626708984,0.05300140380859375,100.3286361694336
4,TO,binary,10,10000,16.081501007080078,16.127498626708984,-0.04599761962890625,99.71478271484375
5,TO,binary,10,10000,16.095001220703125,16.127498626708984,-0.032497406005859375,99.79849243164062
6,TO,binary,10,10000,16.172000885009766,16.127498626708984,0.04450225830078125,100.27594757080078
0,FROM,binary,10,100000,33.053001403808594,33.053001403808594,0.0,100.0
1,FROM,binary,10,100000,34.03200149536133,33.053001403808594,0.9790000915527344,102.96190643310547
2,FROM,binary,10,100000,32.96799850463867,33.053001403808594,-0.08500289916992188,99.74282836914062
3,FROM,binary,10,100000,32.9379997253418,33.053001403808594,-0.11500167846679688,99.65206909179688
4,FROM,binary,10,100000,32.930999755859375,33.053001403808594,-0.12200164794921875,99.63088989257812
5,FROM,binary,10,100000,32.82899856567383,33.053001403808594,-0.22400283813476562,99.3222885131836
6,FROM,binary,10,100000,32.85200119018555,33.053001403808594,-0.20100021362304688,99.39188385009766
0,TO,binary,10,100000,44.25299835205078,44.25299835205078,0.0,100.0
1,TO,binary,10,100000,44.29800033569336,44.25299835205078,0.045001983642578125,100.10169982910156
2,TO,binary,10,100000,44.49100112915039,44.25299835205078,0.23800277709960938,100.53782653808594
3,TO,binary,10,100000,44.314998626708984,44.25299835205078,0.062000274658203125,100.14010620117188
4,TO,binary,10,100000,44.13800048828125,44.25299835205078,-0.11499786376953125,99.7401351928711
5,TO,binary,10,100000,44.34600067138672,44.25299835205078,0.0930023193359375,100.21016693115234
6,TO,binary,10,100000,44.492000579833984,44.25299835205078,0.23900222778320312,100.54007720947266
0,FROM,binary,10,1000000,187.73500061035156,187.73500061035156,0.0,100.0
1,FROM,binary,10,1000000,197.40199279785156,187.73500061035156,9.6669921875,105.14928436279297
2,FROM,binary,10,1000000,186.36199951171875,187.73500061035156,-1.3730010986328125,99.2686538696289
3,FROM,binary,10,1000000,186.75399780273438,187.73500061035156,-0.9810028076171875,99.47745513916016
4,FROM,binary,10,1000000,186.65899658203125,187.73500061035156,-1.0760040283203125,99.42684936523438
5,FROM,binary,10,1000000,186.0679931640625,187.73500061035156,-1.6670074462890625,99.1120376586914
6,FROM,binary,10,1000000,187.53700256347656,187.73500061035156,-0.197998046875,99.89453887939453
0,TO,binary,10,1000000,322.0090026855469,322.0090026855469,0.0,100.0
1,TO,binary,10,1000000,323.15301513671875,322.0090026855469,1.144012451171875,100.35527038574219
2,TO,binary,10,1000000,322.4200134277344,322.0090026855469,0.4110107421875,100.12763977050781
3,TO,binary,10,1000000,321.24200439453125,322.0090026855469,-0.766998291015625,99.76181030273438
4,TO,binary,10,1000000,322.4209899902344,322.0090026855469,0.4119873046875,100.12794494628906
5,TO,binary,10,1000000,322.7279968261719,322.0090026855469,0.718994140625,100.22328186035156
6,TO,binary,10,1000000,328.36199951171875,322.0090026855469,6.352996826171875,101.9729232788086
0,FROM,binary,100,10,13.399999618530273,13.399999618530273,0.0,100.0
1,FROM,binary,100,10,13.36299991607666,13.399999618530273,-0.03699970245361328,99.72388458251953
2,FROM,binary,100,10,13.364999771118164,13.399999618530273,-0.034999847412109375,99.73880767822266
3,FROM,binary,100,10,13.333000183105469,13.399999618530273,-0.06699943542480469,99.50000762939453
4,FROM,binary,100,10,13.451000213623047,13.399999618530273,0.05100059509277344,100.38059997558594
5,FROM,binary,100,10,13.263999938964844,13.399999618530273,-0.1359996795654297,98.98507690429688
6,FROM,binary,100,10,13.354000091552734,13.399999618530273,-0.04599952697753906,99.6567153930664
0,TO,binary,100,10,13.088000297546387,13.088000297546387,0.0,100.0
1,TO,binary,100,10,13.053000450134277,13.088000297546387,-0.034999847412109375,99.73257446289062
2,TO,binary,100,10,13.019000053405762,13.088000297546387,-0.069000244140625,99.47279357910156
3,TO,binary,100,10,13.107000350952148,13.088000297546387,0.01900005340576172,100.14517211914062
4,TO,binary,100,10,13.005999565124512,13.088000297546387,-0.082000732421875,99.37346649169922
5,TO,binary,100,10,13.03499984741211,13.088000297546387,-0.053000450134277344,99.59504699707031
6,TO,binary,100,10,13.097000122070312,13.088000297546387,0.008999824523925781,100.06875610351562
0,FROM,binary,100,100,13.595999717712402,13.595999717712402,0.0,100.0
1,FROM,binary,100,100,13.645000457763672,13.595999717712402,0.04900074005126953,100.36040496826172
2,FROM,binary,100,100,13.680999755859375,13.595999717712402,0.08500003814697266,100.62518310546875
3,FROM,binary,100,100,13.611000061035156,13.595999717712402,0.015000343322753906,100.1103286743164
4,FROM,binary,100,100,13.567999839782715,13.595999717712402,-0.0279998779296875,99.79405975341797
5,FROM,binary,100,100,13.92300033569336,13.595999717712402,0.32700061798095703,102.40512084960938
6,FROM,binary,100,100,13.590999603271484,13.595999717712402,-0.005000114440917969,99.96322631835938
0,TO,binary,100,100,13.267000198364258,13.267000198364258,0.0,100.0
1,TO,binary,100,100,13.199000358581543,13.267000198364258,-0.06799983978271484,99.48745727539062
2,TO,binary,100,100,13.36400032043457,13.267000198364258,0.0970001220703125,100.73113250732422
3,TO,binary,100,100,13.234000205993652,13.267000198364258,-0.03299999237060547,99.75126647949219
4,TO,binary,100,100,13.288000106811523,13.267000198364258,0.020999908447265625,100.15828704833984
5,TO,binary,100,100,13.227999687194824,13.267000198364258,-0.039000511169433594,99.70603942871094
6,TO,binary,100,100,13.28600025177002,13.267000198364258,0.01900005340576172,100.14321899414062
0,FROM,binary,100,1000,17.19099998474121,17.19099998474121,0.0,100.0
1,FROM,binary,100,1000,17.315000534057617,17.19099998474121,0.12400054931640625,100.7213134765625
2,FROM,binary,100,1000,17.222999572753906,17.19099998474121,0.03199958801269531,100.18614196777344
3,FROM,binary,100,1000,17.07900047302246,17.19099998474121,-0.11199951171875,99.34849548339844
4,FROM,binary,100,1000,17.141000747680664,17.19099998474121,-0.049999237060546875,99.70915222167969
5,FROM,binary,100,1000,17.17099952697754,17.19099998474121,-0.020000457763671875,99.88365936279297
6,FROM,binary,100,1000,18.232999801635742,17.19099998474121,1.0419998168945312,106.06131744384766
0,TO,binary,100,1000,15.3100004196167,15.3100004196167,0.0,100.0
1,TO,binary,100,1000,15.289999961853027,15.3100004196167,-0.020000457763671875,99.8693618774414
2,TO,binary,100,1000,15.286999702453613,15.3100004196167,-0.023000717163085938,99.84976959228516
3,TO,binary,100,1000,15.298999786376953,15.3100004196167,-0.011000633239746094,99.92814636230469
4,TO,binary,100,1000,15.206000328063965,15.3100004196167,-0.10400009155273438,99.3207015991211
5,TO,binary,100,1000,15.269000053405762,15.3100004196167,-0.0410003662109375,99.73219299316406
6,TO,binary,100,1000,15.979999542236328,15.3100004196167,0.6699991226196289,104.376220703125
0,FROM,binary,100,10000,29.9060001373291,29.9060001373291,0.0,100.0
1,FROM,binary,100,10000,31.126998901367188,29.9060001373291,1.220998764038086,104.0827865600586
2,FROM,binary,100,10000,29.953500747680664,29.9060001373291,0.0475006103515625,100.1588363647461
3,FROM,binary,100,10000,29.98200035095215,29.9060001373291,0.07600021362304688,100.2541275024414
4,FROM,binary,100,10000,29.874500274658203,29.9060001373291,-0.03149986267089844,99.8946762084961
5,FROM,binary,100,10000,29.931499481201172,29.9060001373291,0.025499343872070312,100.08527374267578
6,FROM,binary,100,10000,29.923500061035156,29.9060001373291,0.017499923706054688,100.05851745605469
0,TO,binary,100,10000,35.21399688720703,35.21399688720703,0.0,100.0
1,TO,binary,100,10000,35.29800033569336,35.21399688720703,0.08400344848632812,100.2385482788086
2,TO,binary,100,10000,35.303001403808594,35.21399688720703,0.0890045166015625,100.25274658203125
3,TO,binary,100,10000,35.28949737548828,35.21399688720703,0.07550048828125,100.21440887451172
4,TO,binary,100,10000,35.38750076293945,35.21399688720703,0.17350387573242188,100.49271392822266
5,TO,binary,100,10000,35.345001220703125,35.21399688720703,0.13100433349609375,100.37202453613281
6,TO,binary,100,10000,36.49850082397461,35.21399688720703,1.2845039367675781,103.647705078125
0,FROM,binary,100,100000,154.4029998779297,154.4029998779297,0.0,100.0
1,FROM,binary,100,100000,165.61900329589844,154.4029998779297,11.21600341796875,107.26411437988281
2,FROM,binary,100,100000,154.4040069580078,154.4029998779297,0.001007080078125,100.00065612792969
3,FROM,binary,100,100000,154.38499450683594,154.4029998779297,-0.01800537109375,99.98834228515625
4,FROM,binary,100,100000,154.1959991455078,154.4029998779297,-0.207000732421875,99.86593627929688
5,FROM,binary,100,100000,154.1699981689453,154.4029998779297,-0.233001708984375,99.84909057617188
6,FROM,binary,100,100000,155.3249969482422,154.4029998779297,0.9219970703125,100.59712982177734
0,TO,binary,100,100000,233.51699829101562,233.51699829101562,0.0,100.0
1,TO,binary,100,100000,233.7519989013672,233.51699829101562,0.2350006103515625,100.10063934326172
2,TO,binary,100,100000,233.6699981689453,233.51699829101562,0.1529998779296875,100.06552124023438
3,TO,binary,100,100000,233.6750030517578,233.51699829101562,0.1580047607421875,100.06766510009766
4,TO,binary,100,100000,233.95799255371094,233.51699829101562,0.4409942626953125,100.18885040283203
5,TO,binary,100,100000,235.12899780273438,233.51699829101562,1.61199951171875,100.69031524658203
6,TO,binary,100,100000,237.58599853515625,233.51699829101562,4.069000244140625,101.74248504638672
0,FROM,binary,100,1000000,1394.050048828125,1394.050048828125,0.0,100.0
1,FROM,binary,100,1000000,1508.9949951171875,1394.050048828125,114.9449462890625,108.24539947509766
2,FROM,binary,100,1000000,1393.989990234375,1394.050048828125,-0.06005859375,99.99568939208984
3,FROM,binary,100,1000000,1396.81201171875,1394.050048828125,2.761962890625,100.19812774658203
4,FROM,binary,100,1000000,1394.300048828125,1394.050048828125,0.25,100.01792907714844
5,FROM,binary,100,1000000,1402.572021484375,1394.050048828125,8.52197265625,100.6113052368164
6,FROM,binary,100,1000000,1416.7010498046875,1394.050048828125,22.6510009765625,101.62483215332031
0,TO,binary,100,1000000,2193.011962890625,2193.011962890625,0.0,100.0
1,TO,binary,100,1000000,2195.593994140625,2193.011962890625,2.58203125,100.11774444580078
2,TO,binary,100,1000000,2195.45703125,2193.011962890625,2.445068359375,100.11149597167969
3,TO,binary,100,1000000,2191.802978515625,2193.011962890625,-1.208984375,99.94486999511719
4,TO,binary,100,1000000,2195.89892578125,2193.011962890625,2.886962890625,100.13164520263672
5,TO,binary,100,1000000,2208.02587890625,2193.011962890625,15.013916015625,100.68463134765625
6,TO,binary,100,1000000,2220.669921875,2193.011962890625,27.657958984375,101.26118469238281
0,FROM,csv,1,10,13.270000457763672,13.270000457763672,0.0,100.0
1,FROM,csv,1,10,13.3100004196167,13.270000457763672,0.039999961853027344,100.30142974853516
2,FROM,csv,1,10,13.206999778747559,13.270000457763672,-0.06300067901611328,99.52523803710938
3,FROM,csv,1,10,13.270999908447266,13.270000457763672,0.00099945068359375,100.00753784179688
4,FROM,csv,1,10,13.256999969482422,13.270000457763672,-0.01300048828125,99.90203094482422
5,FROM,csv,1,10,13.210000038146973,13.270000457763672,-0.06000041961669922,99.5478515625
6,FROM,csv,1,10,13.24899959564209,13.270000457763672,-0.02100086212158203,99.84174346923828
0,TO,csv,1,10,13.015000343322754,13.015000343322754,0.0,100.0
1,TO,csv,1,10,13.109000205993652,13.015000343322754,0.09399986267089844,100.72224426269531
2,TO,csv,1,10,12.970000267028809,13.015000343322754,-0.04500007629394531,99.65424346923828
3,TO,csv,1,10,13.097000122070312,13.015000343322754,0.0819997787475586,100.63004302978516
4,TO,csv,1,10,12.928000450134277,13.015000343322754,-0.08699989318847656,99.33154296875
5,TO,csv,1,10,13.045999526977539,13.015000343322754,0.030999183654785156,100.2381820678711
6,TO,csv,1,10,13.07699966430664,13.015000343322754,0.06199932098388672,100.47637176513672
0,FROM,csv,1,100,13.428000450134277,13.428000450134277,0.0,100.0
1,FROM,csv,1,100,13.357000350952148,13.428000450134277,-0.0710000991821289,99.47125244140625
2,FROM,csv,1,100,13.484999656677246,13.428000450134277,0.05699920654296875,100.42448425292969
3,FROM,csv,1,100,13.350000381469727,13.428000450134277,-0.07800006866455078,99.41912078857422
4,FROM,csv,1,100,13.321999549865723,13.428000450134277,-0.10600090026855469,99.2105941772461
5,FROM,csv,1,100,13.38599967956543,13.428000450134277,-0.042000770568847656,99.68721008300781
6,FROM,csv,1,100,13.493000030517578,13.428000450134277,0.06499958038330078,100.48406219482422
0,TO,csv,1,100,13.100000381469727,13.100000381469727,0.0,100.0
1,TO,csv,1,100,13.005000114440918,13.100000381469727,-0.0950002670288086,99.27481079101562
2,TO,csv,1,100,13.062999725341797,13.100000381469727,-0.03700065612792969,99.7175521850586
3,TO,csv,1,100,12.961999893188477,13.100000381469727,-0.13800048828125,98.9465560913086
4,TO,csv,1,100,12.996000289916992,13.100000381469727,-0.10400009155273438,99.20610809326172
5,TO,csv,1,100,13.017000198364258,13.100000381469727,-0.08300018310546875,99.36640930175781
6,TO,csv,1,100,13.104999542236328,13.100000381469727,0.0049991607666015625,100.03816223144531
0,FROM,csv,1,1000,15.380000114440918,15.380000114440918,0.0,100.0
1,FROM,csv,1,1000,15.329999923706055,15.380000114440918,-0.05000019073486328,99.67489624023438
2,FROM,csv,1,1000,15.392999649047852,15.380000114440918,0.012999534606933594,100.08451843261719
3,FROM,csv,1,1000,15.607000350952148,15.380000114440918,0.22700023651123047,101.47594451904297
4,FROM,csv,1,1000,15.338000297546387,15.380000114440918,-0.04199981689453125,99.72692108154297
5,FROM,csv,1,1000,15.46500015258789,15.380000114440918,0.08500003814697266,100.55266571044922
6,FROM,csv,1,1000,15.449999809265137,15.380000114440918,0.06999969482421875,100.45513153076172
0,TO,csv,1,1000,13.180999755859375,13.180999755859375,0.0,100.0
1,TO,csv,1,1000,13.11299991607666,13.180999755859375,-0.06799983978271484,99.4841079711914
2,TO,csv,1,1000,13.10200023651123,13.180999755859375,-0.07899951934814453,99.4006576538086
3,TO,csv,1,1000,13.11400032043457,13.180999755859375,-0.06699943542480469,99.49169921875
4,TO,csv,1,1000,13.071000099182129,13.180999755859375,-0.1099996566772461,99.16546630859375
5,TO,csv,1,1000,13.034000396728516,13.180999755859375,-0.14699935913085938,98.88475799560547
6,TO,csv,1,1000,13.027000427246094,13.180999755859375,-0.15399932861328125,98.83165740966797
0,FROM,csv,1,10000,15.999500274658203,15.999500274658203,0.0,100.0
1,FROM,csv,1,10000,15.931499481201172,15.999500274658203,-0.06800079345703125,99.57498168945312
2,FROM,csv,1,10000,15.999500274658203,15.999500274658203,0.0,100.0
3,FROM,csv,1,10000,16.02750015258789,15.999500274658203,0.0279998779296875,100.17500305175781
4,FROM,csv,1,10000,15.946000099182129,15.999500274658203,-0.05350017547607422,99.66561126708984
5,FROM,csv,1,10000,15.965999603271484,15.999500274658203,-0.03350067138671875,99.79061126708984
6,FROM,csv,1,10000,16.01849937438965,15.999500274658203,0.018999099731445312,100.11874389648438
0,TO,csv,1,10000,13.867000579833984,13.867000579833984,0.0,100.0
1,TO,csv,1,10000,13.838000297546387,13.867000579833984,-0.029000282287597656,99.7908706665039
2,TO,csv,1,10000,13.829999923706055,13.867000579833984,-0.03700065612792969,99.7331771850586
3,TO,csv,1,10000,13.906499862670898,13.867000579833984,0.03949928283691406,100.28483581542969
4,TO,csv,1,10000,13.818500518798828,13.867000579833984,-0.04850006103515625,99.6502456665039
5,TO,csv,1,10000,13.875,13.867000579833984,0.007999420166015625,100.05768585205078
6,TO,csv,1,10000,13.878000259399414,13.867000579833984,0.010999679565429688,100.0793228149414
0,FROM,csv,1,100000,21.645999908447266,21.645999908447266,0.0,100.0
1,FROM,csv,1,100000,21.51300048828125,21.645999908447266,-0.13299942016601562,99.38557434082031
2,FROM,csv,1,100000,21.79800033569336,21.645999908447266,0.15200042724609375,100.70221710205078
3,FROM,csv,1,100000,21.979000091552734,21.645999908447266,0.33300018310546875,101.53839874267578
4,FROM,csv,1,100000,21.660999298095703,21.645999908447266,0.0149993896484375,100.06929779052734
5,FROM,csv,1,100000,21.559999465942383,21.645999908447266,-0.08600044250488281,99.60269165039062
6,FROM,csv,1,100000,21.625,21.645999908447266,-0.020999908447265625,99.90298461914062
0,TO,csv,1,100000,21.805999755859375,21.805999755859375,0.0,100.0
1,TO,csv,1,100000,21.701000213623047,21.805999755859375,-0.10499954223632812,99.51848602294922
2,TO,csv,1,100000,21.836999893188477,21.805999755859375,0.031000137329101562,100.14216613769531
3,TO,csv,1,100000,21.77400016784668,21.805999755859375,-0.03199958801269531,99.85325622558594
4,TO,csv,1,100000,21.982999801635742,21.805999755859375,0.1770000457763672,100.81170654296875
5,TO,csv,1,100000,21.756999969482422,21.805999755859375,-0.048999786376953125,99.7752914428711
6,TO,csv,1,100000,21.781999588012695,21.805999755859375,-0.024000167846679688,99.88993835449219
0,FROM,csv,1,1000000,77.04900360107422,77.04900360107422,0.0,100.0
1,FROM,csv,1,1000000,77.24500274658203,77.04900360107422,0.1959991455078125,100.25437927246094
2,FROM,csv,1,1000000,78.75800323486328,77.04900360107422,1.7089996337890625,102.21807098388672
3,FROM,csv,1,1000000,81.177001953125,77.04900360107422,4.127998352050781,105.35762023925781
4,FROM,csv,1,1000000,78.0459976196289,77.04900360107422,0.9969940185546875,101.2939682006836
5,FROM,csv,1,1000000,77.70899963378906,77.04900360107422,0.6599960327148438,100.8565902709961
6,FROM,csv,1,1000000,77.56600189208984,77.04900360107422,0.516998291015625,100.67100524902344
0,TO,csv,1,1000000,98.2300033569336,98.2300033569336,0.0,100.0
1,TO,csv,1,1000000,98.22599792480469,98.2300033569336,-0.00400543212890625,99.99592590332031
2,TO,csv,1,1000000,98.072998046875,98.2300033569336,-0.15700531005859375,99.84016418457031
3,TO,csv,1,1000000,98.22899627685547,98.2300033569336,-0.001007080078125,99.99897766113281
4,TO,csv,1,1000000,99.08399963378906,98.2300033569336,0.8539962768554688,100.869384765625
5,TO,csv,1,1000000,97.8489990234375,98.2300033569336,-0.38100433349609375,99.61212921142578
6,TO,csv,1,1000000,97.81400299072266,98.2300033569336,-0.4160003662109375,99.57649993896484
0,FROM,csv,10,10,13.199999809265137,13.199999809265137,0.0,100.0
1,FROM,csv,10,10,13.279000282287598,13.199999809265137,0.07900047302246094,100.5984878540039
2,FROM,csv,10,10,13.369000434875488,13.199999809265137,0.16900062561035156,101.28030395507812
3,FROM,csv,10,10,13.279999732971191,13.199999809265137,0.07999992370605469,100.60606384277344
4,FROM,csv,10,10,13.293999671936035,13.199999809265137,0.09399986267089844,100.71212005615234
5,FROM,csv,10,10,13.23900032043457,13.199999809265137,0.039000511169433594,100.29546356201172
6,FROM,csv,10,10,13.303999900817871,13.199999809265137,0.10400009155273438,100.78787994384766
0,TO,csv,10,10,13.189000129699707,13.189000129699707,0.0,100.0
1,TO,csv,10,10,12.888999938964844,13.189000129699707,-0.3000001907348633,97.72537231445312
2,TO,csv,10,10,12.996999740600586,13.189000129699707,-0.1920003890991211,98.54424285888672
3,TO,csv,10,10,13.07800006866455,13.189000129699707,-0.11100006103515625,99.15838623046875
4,TO,csv,10,10,12.963000297546387,13.189000129699707,-0.2259998321533203,98.28645324707031
5,TO,csv,10,10,13.003999710083008,13.189000129699707,-0.18500041961669922,98.5973129272461
6,TO,csv,10,10,13.027000427246094,13.189000129699707,-0.16199970245361328,98.7717056274414
0,FROM,csv,10,100,13.468999862670898,13.468999862670898,0.0,100.0
1,FROM,csv,10,100,13.401000022888184,13.468999862670898,-0.06799983978271484,99.4951400756836
2,FROM,csv,10,100,13.276000022888184,13.468999862670898,-0.19299983978271484,98.56707763671875
3,FROM,csv,10,100,13.50100040435791,13.468999862670898,0.03200054168701172,100.23758697509766
4,FROM,csv,10,100,13.362000465393066,13.468999862670898,-0.10699939727783203,99.2055892944336
5,FROM,csv,10,100,13.307000160217285,13.468999862670898,-0.16199970245361328,98.7972412109375
6,FROM,csv,10,100,13.48900032043457,13.468999862670898,0.020000457763671875,100.14848327636719
0,TO,csv,10,100,12.894000053405762,12.894000053405762,0.0,100.0
1,TO,csv,10,100,13.0,12.894000053405762,0.10599994659423828,100.82209014892578
2,TO,csv,10,100,13.161999702453613,12.894000053405762,0.26799964904785156,102.07848358154297
3,TO,csv,10,100,13.020000457763672,12.894000053405762,0.12600040435791016,100.97720336914062
4,TO,csv,10,100,12.944000244140625,12.894000053405762,0.05000019073486328,100.38777923583984
5,TO,csv,10,100,13.03600025177002,12.894000053405762,0.1420001983642578,101.10128784179688
6,TO,csv,10,100,13.008000373840332,12.894000053405762,0.11400032043457031,100.88414001464844
0,FROM,csv,10,1000,15.680000305175781,15.680000305175781,0.0,100.0
1,FROM,csv,10,1000,15.664999961853027,15.680000305175781,-0.015000343322753906,99.90433502197266
2,FROM,csv,10,1000,15.659000396728516,15.680000305175781,-0.020999908447265625,99.86607360839844
3,FROM,csv,10,1000,15.619999885559082,15.680000305175781,-0.06000041961669922,99.61734771728516
4,FROM,csv,10,1000,15.753000259399414,15.680000305175781,0.07299995422363281,100.46556091308594
5,FROM,csv,10,1000,15.685999870300293,15.680000305175781,0.005999565124511719,100.03826904296875
6,FROM,csv,10,1000,15.656000137329102,15.680000305175781,-0.024000167846679688,99.84693908691406
0,TO,csv,10,1000,13.25100040435791,13.25100040435791,0.0,100.0
1,TO,csv,10,1000,13.156999588012695,13.25100040435791,-0.09400081634521484,99.29061889648438
2,TO,csv,10,1000,13.24899959564209,13.25100040435791,-0.0020008087158203125,99.98490142822266
3,TO,csv,10,1000,13.340999603271484,13.25100040435791,0.08999919891357422,100.67918395996094
4,TO,csv,10,1000,13.220999717712402,13.25100040435791,-0.030000686645507812,99.77359771728516
5,TO,csv,10,1000,13.27299976348877,13.25100040435791,0.021999359130859375,100.16602325439453
6,TO,csv,10,1000,13.152999877929688,13.25100040435791,-0.09800052642822266,99.26042938232422
0,FROM,csv,10,10000,17.73550033569336,17.73550033569336,0.0,100.0
1,FROM,csv,10,10000,17.63800048828125,17.73550033569336,-0.09749984741210938,99.45025634765625
2,FROM,csv,10,10000,17.658000946044922,17.73550033569336,-0.0774993896484375,99.56302642822266
3,FROM,csv,10,10000,17.691999435424805,17.73550033569336,-0.04350090026855469,99.75473022460938
4,FROM,csv,10,10000,17.6614990234375,17.73550033569336,-0.07400131225585938,99.58274841308594
5,FROM,csv,10,10000,17.689998626708984,17.73550033569336,-0.045501708984375,99.74344635009766
6,FROM,csv,10,10000,17.66349983215332,17.73550033569336,-0.07200050354003906,99.59403228759766
0,TO,csv,10,10000,15.515999794006348,15.515999794006348,0.0,100.0
1,TO,csv,10,10000,15.48900032043457,15.515999794006348,-0.026999473571777344,99.82598876953125
2,TO,csv,10,10000,15.487499237060547,15.515999794006348,-0.02850055694580078,99.81631469726562
3,TO,csv,10,10000,15.444000244140625,15.515999794006348,-0.07199954986572266,99.53596496582031
4,TO,csv,10,10000,15.430999755859375,15.515999794006348,-0.08500003814697266,99.45217895507812
5,TO,csv,10,10000,15.435500144958496,15.515999794006348,-0.08049964904785156,99.48118591308594
6,TO,csv,10,10000,15.46399974822998,15.515999794006348,-0.05200004577636719,99.66486358642578
0,FROM,csv,10,100000,37.722999572753906,37.722999572753906,0.0,100.0
1,FROM,csv,10,100000,37.56100082397461,37.722999572753906,-0.16199874877929688,99.570556640625
2,FROM,csv,10,100000,38.13600158691406,37.722999572753906,0.41300201416015625,101.09483337402344
3,FROM,csv,10,100000,38.130001068115234,37.722999572753906,0.4070014953613281,101.07891845703125
4,FROM,csv,10,100000,37.91400146484375,37.722999572753906,0.19100189208984375,100.50633239746094
5,FROM,csv,10,100000,37.79100036621094,37.722999572753906,0.06800079345703125,100.18026733398438
6,FROM,csv,10,100000,37.86399841308594,37.722999572753906,0.14099884033203125,100.37377166748047
0,TO,csv,10,100000,37.6510009765625,37.6510009765625,0.0,100.0
1,TO,csv,10,100000,37.45800018310547,37.6510009765625,-0.19300079345703125,99.48739624023438
2,TO,csv,10,100000,37.42900085449219,37.6510009765625,-0.2220001220703125,99.41036987304688
3,TO,csv,10,100000,37.486000061035156,37.6510009765625,-0.16500091552734375,99.56175994873047
4,TO,csv,10,100000,37.500999450683594,37.6510009765625,-0.15000152587890625,99.60160064697266
5,TO,csv,10,100000,37.729000091552734,37.6510009765625,0.07799911499023438,100.20716094970703
6,TO,csv,10,100000,37.63999938964844,37.6510009765625,-0.0110015869140625,99.97077941894531
0,FROM,csv,10,1000000,237.156005859375,237.156005859375,0.0,100.0
1,FROM,csv,10,1000000,237.5240020751953,237.156005859375,0.3679962158203125,100.1551742553711
2,FROM,csv,10,1000000,239.1179962158203,237.156005859375,1.9619903564453125,100.82730102539062
3,FROM,csv,10,1000000,240.03700256347656,237.156005859375,2.8809967041015625,101.21481323242188
4,FROM,csv,10,1000000,238.98300170898438,237.156005859375,1.826995849609375,100.77037811279297
5,FROM,csv,10,1000000,238.94200134277344,237.156005859375,1.7859954833984375,100.75308990478516
6,FROM,csv,10,1000000,238.46499633789062,237.156005859375,1.308990478515625,100.55194854736328
0,TO,csv,10,1000000,255.98399353027344,255.98399353027344,0.0,100.0
1,TO,csv,10,1000000,253.25599670410156,255.98399353027344,-2.727996826171875,98.93431091308594
2,TO,csv,10,1000000,253.21800231933594,255.98399353027344,-2.7659912109375,98.91947174072266
3,TO,csv,10,1000000,253.86000061035156,255.98399353027344,-2.123992919921875,99.1702651977539
4,TO,csv,10,1000000,254.45199584960938,255.98399353027344,-1.5319976806640625,99.40152740478516
5,TO,csv,10,1000000,255.39599609375,255.98399353027344,-0.5879974365234375,99.77030181884766
6,TO,csv,10,1000000,257.6860046386719,255.98399353027344,1.7020111083984375,100.66488647460938
0,FROM,csv,100,10,13.286999702453613,13.286999702453613,0.0,100.0
1,FROM,csv,100,10,13.37399959564209,13.286999702453613,0.08699989318847656,100.65476989746094
2,FROM,csv,100,10,13.383999824523926,13.286999702453613,0.0970001220703125,100.73004150390625
3,FROM,csv,100,10,13.255000114440918,13.286999702453613,-0.03199958801269531,99.75917053222656
4,FROM,csv,100,10,13.29800033569336,13.286999702453613,0.011000633239746094,100.08279418945312
5,FROM,csv,100,10,13.312000274658203,13.286999702453613,0.025000572204589844,100.18815612792969
6,FROM,csv,100,10,13.467000007629395,13.286999702453613,0.18000030517578125,101.35470581054688
0,TO,csv,100,10,13.361000061035156,13.361000061035156,0.0,100.0
1,TO,csv,100,10,13.005000114440918,13.361000061035156,-0.3559999465942383,97.33552551269531
2,TO,csv,100,10,13.015999794006348,13.361000061035156,-0.3450002670288086,97.41785430908203
3,TO,csv,100,10,13.175999641418457,13.361000061035156,-0.18500041961669922,98.61537170410156
4,TO,csv,100,10,13.020999908447266,13.361000061035156,-0.3400001525878906,97.45528411865234
5,TO,csv,100,10,13.008999824523926,13.361000061035156,-0.35200023651123047,97.36546325683594
6,TO,csv,100,10,13.055999755859375,13.361000061035156,-0.30500030517578125,97.71723175048828
0,FROM,csv,100,100,13.704999923706055,13.704999923706055,0.0,100.0
1,FROM,csv,100,100,13.694000244140625,13.704999923706055,-0.010999679565429688,99.91973876953125
2,FROM,csv,100,100,13.734999656677246,13.704999923706055,0.029999732971191406,100.2188949584961
3,FROM,csv,100,100,13.76099967956543,13.704999923706055,0.055999755859375,100.40861511230469
4,FROM,csv,100,100,13.696999549865723,13.704999923706055,-0.008000373840332031,99.94161987304688
5,FROM,csv,100,100,13.708999633789062,13.704999923706055,0.0039997100830078125,100.02918243408203
6,FROM,csv,100,100,13.689000129699707,13.704999923706055,-0.015999794006347656,99.88325500488281
0,TO,csv,100,100,13.163000106811523,13.163000106811523,0.0,100.0
1,TO,csv,100,100,13.14900016784668,13.163000106811523,-0.01399993896484375,99.89363861083984
2,TO,csv,100,100,13.22700023651123,13.163000106811523,0.06400012969970703,100.4862060546875
3,TO,csv,100,100,13.222999572753906,13.163000106811523,0.05999946594238281,100.45581817626953
4,TO,csv,100,100,13.107999801635742,13.163000106811523,-0.05500030517578125,99.58216094970703
5,TO,csv,100,100,13.218000411987305,13.163000106811523,0.05500030517578125,100.41783905029297
6,TO,csv,100,100,13.229999542236328,13.163000106811523,0.06699943542480469,100.50900268554688
0,FROM,csv,100,1000,15.87399959564209,15.87399959564209,0.0,100.0
1,FROM,csv,100,1000,15.862000465393066,15.87399959564209,-0.011999130249023438,99.92440795898438
2,FROM,csv,100,1000,15.869000434875488,15.87399959564209,-0.0049991607666015625,99.968505859375
3,FROM,csv,100,1000,15.956999778747559,15.87399959564209,0.08300018310546875,100.52286529541016
4,FROM,csv,100,1000,15.814000129699707,15.87399959564209,-0.05999946594238281,99.62203216552734
5,FROM,csv,100,1000,15.835000038146973,15.87399959564209,-0.03899955749511719,99.75431823730469
6,FROM,csv,100,1000,15.826000213623047,15.87399959564209,-0.04799938201904297,99.69761657714844
0,TO,csv,100,1000,14.848999977111816,14.848999977111816,0.0,100.0
1,TO,csv,100,1000,14.772000312805176,14.848999977111816,-0.07699966430664062,99.48145294189453
2,TO,csv,100,1000,14.817000389099121,14.848999977111816,-0.03199958801269531,99.78450012207031
3,TO,csv,100,1000,14.8100004196167,14.848999977111816,-0.03899955749511719,99.73735809326172
4,TO,csv,100,1000,14.807999610900879,14.848999977111816,-0.0410003662109375,99.72388458251953
5,TO,csv,100,1000,14.836000442504883,14.848999977111816,-0.012999534606933594,99.9124526977539
6,TO,csv,100,1000,14.850000381469727,14.848999977111816,0.0010004043579101562,100.0067367553711
0,FROM,csv,100,10000,33.63650131225586,33.63650131225586,0.0,100.0
1,FROM,csv,100,10000,33.4995002746582,33.63650131225586,-0.13700103759765625,99.59270477294922
2,FROM,csv,100,10000,33.77400207519531,33.63650131225586,0.13750076293945312,100.40878295898438
3,FROM,csv,100,10000,33.86249923706055,33.63650131225586,0.2259979248046875,100.67189025878906
4,FROM,csv,100,10000,33.79750061035156,33.63650131225586,0.16099929809570312,100.47865295410156
5,FROM,csv,100,10000,33.77299880981445,33.63650131225586,0.13649749755859375,100.40579986572266
6,FROM,csv,100,10000,33.72949981689453,33.63650131225586,0.09299850463867188,100.27648162841797
0,TO,csv,100,10000,30.89699935913086,30.89699935913086,0.0,100.0
1,TO,csv,100,10000,30.49250030517578,30.89699935913086,-0.4044990539550781,98.69081115722656
2,TO,csv,100,10000,30.62350082397461,30.89699935913086,-0.27349853515625,99.11480712890625
3,TO,csv,100,10000,30.540000915527344,30.89699935913086,-0.3569984436035156,98.84455108642578
4,TO,csv,100,10000,30.535499572753906,30.89699935913086,-0.3614997863769531,98.82998657226562
5,TO,csv,100,10000,30.772499084472656,30.89699935913086,-0.12450027465820312,99.5970458984375
6,TO,csv,100,10000,30.98900032043457,30.89699935913086,0.09200096130371094,100.29776000976562
0,FROM,csv,100,100000,211.65899658203125,211.65899658203125,0.0,100.0
1,FROM,csv,100,100000,209.0959930419922,211.65899658203125,-2.5630035400390625,98.78909301757812
2,FROM,csv,100,100000,210.46299743652344,211.65899658203125,-1.1959991455078125,99.43494415283203
3,FROM,csv,100,100000,212.07400512695312,211.65899658203125,0.415008544921875,100.19607543945312
4,FROM,csv,100,100000,211.6529998779297,211.65899658203125,-0.0059967041015625,99.9971694946289
5,FROM,csv,100,100000,211.26300048828125,211.65899658203125,-0.39599609375,99.81290435791016
6,FROM,csv,100,100000,212.0570068359375,211.65899658203125,0.39801025390625,100.18804168701172
0,TO,csv,100,100000,189.71299743652344,189.71299743652344,0.0,100.0
1,TO,csv,100,100000,185.96800231933594,189.71299743652344,-3.7449951171875,98.02596282958984
2,TO,csv,100,100000,186.47000122070312,189.71299743652344,-3.2429962158203125,98.29058074951172
3,TO,csv,100,100000,186.40499877929688,189.71299743652344,-3.3079986572265625,98.25631713867188
4,TO,csv,100,100000,186.3800048828125,189.71299743652344,-3.3329925537109375,98.2431411743164
5,TO,csv,100,100000,189.66600036621094,189.71299743652344,-0.0469970703125,99.97522735595703
6,TO,csv,100,100000,192.23699951171875,189.71299743652344,2.5240020751953125,101.33043670654297
0,FROM,csv,100,1000000,1971.9420166015625,1971.9420166015625,0.0,100.0
1,FROM,csv,100,1000000,1978.2349853515625,1971.9420166015625,6.29296875,100.31912231445312
2,FROM,csv,100,1000000,1999.2889404296875,1971.9420166015625,27.346923828125,101.38679504394531
3,FROM,csv,100,1000000,1988.7679443359375,1971.9420166015625,16.825927734375,100.85326385498047
4,FROM,csv,100,1000000,2000.845947265625,1971.9420166015625,28.9039306640625,101.46575927734375
5,FROM,csv,100,1000000,1987.072021484375,1971.9420166015625,15.1300048828125,100.76726531982422
6,FROM,csv,100,1000000,1988.1400146484375,1971.9420166015625,16.197998046875,100.82142639160156
0,TO,csv,100,1000000,1758.739990234375,1758.739990234375,0.0,100.0
1,TO,csv,100,1000000,1727.56201171875,1758.739990234375,-31.177978515625,98.22725677490234
2,TO,csv,100,1000000,1727.2950439453125,1758.739990234375,-31.4449462890625,98.21207427978516
3,TO,csv,100,1000000,1727.251953125,1758.739990234375,-31.488037109375,98.20962524414062
4,TO,csv,100,1000000,1731.0250244140625,1758.739990234375,-27.7149658203125,98.42416381835938
5,TO,csv,100,1000000,1775.573974609375,1758.739990234375,16.833984375,100.95716857910156
6,TO,csv,100,1000000,1770.58203125,1758.739990234375,11.842041015625,100.67333221435547
0,FROM,text,1,10,14.281000137329102,14.281000137329102,0.0,100.0
1,FROM,text,1,10,13.343000411987305,14.281000137329102,-0.9379997253417969,93.43183898925781
2,FROM,text,1,10,14.11299991607666,14.281000137329102,-0.1680002212524414,98.82361602783203
3,FROM,text,1,10,14.482000350952148,14.281000137329102,0.20100021362304688,101.407470703125
4,FROM,text,1,10,14.135000228881836,14.281000137329102,-0.14599990844726562,98.9776611328125
5,FROM,text,1,10,14.36299991607666,14.281000137329102,0.0819997787475586,100.57418060302734
6,FROM,text,1,10,13.3100004196167,14.281000137329102,-0.9709997177124023,93.20075988769531
0,TO,text,1,10,14.529999732971191,14.529999732971191,0.0,100.0
1,TO,text,1,10,13.340999603271484,14.529999732971191,-1.189000129699707,91.81693267822266
2,TO,text,1,10,13.944000244140625,14.529999732971191,-0.5859994888305664,95.96697235107422
3,TO,text,1,10,14.152000427246094,14.529999732971191,-0.37799930572509766,97.39849090576172
4,TO,text,1,10,13.914999961853027,14.529999732971191,-0.6149997711181641,95.76737976074219
5,TO,text,1,10,13.835000038146973,14.529999732971191,-0.6949996948242188,95.21678924560547
6,TO,text,1,10,12.914999961853027,14.529999732971191,-1.614999771118164,88.88507080078125
0,FROM,text,1,100,13.888999938964844,13.888999938964844,0.0,100.0
1,FROM,text,1,100,13.090999603271484,13.888999938964844,-0.7980003356933594,94.25444793701172
2,FROM,text,1,100,14.456999778747559,13.888999938964844,0.5679998397827148,104.08956909179688
3,FROM,text,1,100,14.071000099182129,13.888999938964844,0.18200016021728516,101.31039428710938
4,FROM,text,1,100,14.359999656677246,13.888999938964844,0.47099971771240234,103.39117431640625
5,FROM,text,1,100,14.425000190734863,13.888999938964844,0.5360002517700195,103.85917663574219
6,FROM,text,1,100,13.111000061035156,13.888999938964844,-0.7779998779296875,94.39844512939453
0,TO,text,1,100,13.57800006866455,13.57800006866455,0.0,100.0
1,TO,text,1,100,13.479999542236328,13.57800006866455,-0.09800052642822266,99.27824401855469
2,TO,text,1,100,13.92300033569336,13.57800006866455,0.3450002670288086,102.54087829589844
3,TO,text,1,100,13.706000328063965,13.57800006866455,0.12800025939941406,100.94270324707031
4,TO,text,1,100,13.911999702453613,13.57800006866455,0.3339996337890625,102.4598617553711
5,TO,text,1,100,14.045999526977539,13.57800006866455,0.4679994583129883,103.44674682617188
6,TO,text,1,100,13.407999992370605,13.57800006866455,-0.1700000762939453,98.74797821044922
0,FROM,text,1,1000,15.218999862670898,15.218999862670898,0.0,100.0
1,FROM,text,1,1000,16.06100082397461,15.218999862670898,0.8420009613037109,105.53256225585938
2,FROM,text,1,1000,15.869999885559082,15.218999862670898,0.6510000228881836,104.27754974365234
3,FROM,text,1,1000,15.314000129699707,15.218999862670898,0.0950002670288086,100.62421417236328
4,FROM,text,1,1000,15.520000457763672,15.218999862670898,0.30100059509277344,101.97779083251953
5,FROM,text,1,1000,16.204999923706055,15.218999862670898,0.9860000610351562,106.4787368774414
6,FROM,text,1,1000,16.101999282836914,15.218999862670898,0.8829994201660156,105.80194854736328
0,TO,text,1,1000,13.154000282287598,13.154000282287598,0.0,100.0
1,TO,text,1,1000,12.85099983215332,13.154000282287598,-0.30300045013427734,97.6965103149414
2,TO,text,1,1000,13.491999626159668,13.154000282287598,0.3379993438720703,102.5695571899414
3,TO,text,1,1000,12.72700023651123,13.154000282287598,-0.4270000457763672,96.75384521484375
4,TO,text,1,1000,13.675999641418457,13.154000282287598,0.5219993591308594,103.96836853027344
5,TO,text,1,1000,13.8100004196167,13.154000282287598,0.6560001373291016,104.98707580566406
6,TO,text,1,1000,13.529000282287598,13.154000282287598,0.375,102.85084533691406
0,FROM,text,1,10000,16.60449981689453,16.60449981689453,0.0,100.0
1,FROM,text,1,10000,16.79450035095215,16.60449981689453,0.1900005340576172,101.1442642211914
2,FROM,text,1,10000,16.220500946044922,16.60449981689453,-0.3839988708496094,97.6873779296875
3,FROM,text,1,10000,16.054500579833984,16.60449981689453,-0.5499992370605469,96.68765258789062
4,FROM,text,1,10000,16.24100112915039,16.60449981689453,-0.3634986877441406,97.81083679199219
5,FROM,text,1,10000,15.780500411987305,16.60449981689453,-0.8239994049072266,95.0374984741211
6,FROM,text,1,10000,16.985000610351562,16.60449981689453,0.38050079345703125,102.29154968261719
0,TO,text,1,10000,14.281499862670898,14.281499862670898,0.0,100.0
1,TO,text,1,10000,14.458499908447266,14.281499862670898,0.1770000457763672,101.23937225341797
2,TO,text,1,10000,14.333999633789062,14.281499862670898,0.05249977111816406,100.36760711669922
3,TO,text,1,10000,13.857999801635742,14.281499862670898,-0.42350006103515625,97.03462982177734
4,TO,text,1,10000,14.16200065612793,14.281499862670898,-0.11949920654296875,99.16326141357422
5,TO,text,1,10000,13.511499404907227,14.281499862670898,-0.7700004577636719,94.60840606689453
6,TO,text,1,10000,14.631000518798828,14.281499862670898,0.3495006561279297,102.44721984863281
0,FROM,text,1,100000,22.43199920654297,22.43199920654297,0.0,100.0
1,FROM,text,1,100000,22.516000747680664,22.43199920654297,0.08400154113769531,100.37447357177734
2,FROM,text,1,100000,22.14699935913086,22.43199920654297,-0.2849998474121094,98.72949981689453
3,FROM,text,1,100000,22.493000030517578,22.43199920654297,0.061000823974609375,100.27194213867188
4,FROM,text,1,100000,22.281999588012695,22.43199920654297,-0.14999961853027344,99.33131408691406
5,FROM,text,1,100000,22.209999084472656,22.43199920654297,-0.2220001220703125,99.01034545898438
6,FROM,text,1,100000,22.64900016784668,22.43199920654297,0.21700096130371094,100.96736907958984
0,TO,text,1,100000,21.861000061035156,21.861000061035156,0.0,100.0
1,TO,text,1,100000,22.180999755859375,21.861000061035156,0.31999969482421875,101.46379089355469
2,TO,text,1,100000,21.60700035095215,21.861000061035156,-0.2539997100830078,98.8381118774414
3,TO,text,1,100000,21.886999130249023,21.861000061035156,0.025999069213867188,100.11892700195312
4,TO,text,1,100000,21.631999969482422,21.861000061035156,-0.22900009155273438,98.95246887207031
5,TO,text,1,100000,21.492000579833984,21.861000061035156,-0.3689994812011719,98.31206512451172
6,TO,text,1,100000,22.131000518798828,21.861000061035156,0.2700004577636719,101.23507690429688
0,FROM,text,1,1000000,77.4739990234375,77.4739990234375,0.0,100.0
1,FROM,text,1,1000000,75.95099639892578,77.4739990234375,-1.5230026245117188,98.03417205810547
2,FROM,text,1,1000000,78.76899719238281,77.4739990234375,1.2949981689453125,101.6715316772461
3,FROM,text,1,1000000,79.9530029296875,77.4739990234375,2.47900390625,103.19979095458984
4,FROM,text,1,1000000,77.58300018310547,77.4739990234375,0.10900115966796875,100.14069366455078
5,FROM,text,1,1000000,78.68599700927734,77.4739990234375,1.2119979858398438,101.56439208984375
6,FROM,text,1,1000000,76.61499786376953,77.4739990234375,-0.8590011596679688,98.89124298095703
0,TO,text,1,1000000,93.4990005493164,93.4990005493164,0.0,100.0
1,TO,text,1,1000000,94.1259994506836,93.4990005493164,0.6269989013671875,100.67060089111328
2,TO,text,1,1000000,93.1259994506836,93.4990005493164,-0.3730010986328125,99.60106658935547
3,TO,text,1,1000000,93.11799621582031,93.4990005493164,-0.38100433349609375,99.5925064086914
4,TO,text,1,1000000,93.82499694824219,93.4990005493164,0.32599639892578125,100.34866333007812
5,TO,text,1,1000000,93.0989990234375,93.4990005493164,-0.40000152587890625,99.57218933105469
6,TO,text,1,1000000,93.49199676513672,93.4990005493164,-0.0070037841796875,99.99250793457031
0,FROM,text,10,10,14.373000144958496,14.373000144958496,0.0,100.0
1,FROM,text,10,10,12.986000061035156,14.373000144958496,-1.3870000839233398,90.34996032714844
2,FROM,text,10,10,14.361000061035156,14.373000144958496,-0.012000083923339844,99.91651153564453
3,FROM,text,10,10,13.99899959564209,14.373000144958496,-0.37400054931640625,97.39789581298828
4,FROM,text,10,10,14.08899974822998,14.373000144958496,-0.2840003967285156,98.0240707397461
5,FROM,text,10,10,13.961999893188477,14.373000144958496,-0.41100025177001953,97.14046478271484
6,FROM,text,10,10,13.0600004196167,14.373000144958496,-1.3129997253417969,90.86482238769531
0,TO,text,10,10,13.934000015258789,13.934000015258789,0.0,100.0
1,TO,text,10,10,12.645000457763672,13.934000015258789,-1.2889995574951172,90.74925231933594
2,TO,text,10,10,13.98900032043457,13.934000015258789,0.05500030517578125,100.39472961425781
3,TO,text,10,10,14.005999565124512,13.934000015258789,0.07199954986572266,100.51671600341797
4,TO,text,10,10,14.121000289916992,13.934000015258789,0.18700027465820312,101.34204864501953
5,TO,text,10,10,13.894000053405762,13.934000015258789,-0.039999961853027344,99.71292877197266
6,TO,text,10,10,13.196000099182129,13.934000015258789,-0.7379999160766602,94.70360565185547
0,FROM,text,10,100,13.46399974822998,13.46399974822998,0.0,100.0
1,FROM,text,10,100,13.105999946594238,13.46399974822998,-0.3579998016357422,97.341064453125
2,FROM,text,10,100,13.48900032043457,13.46399974822998,0.025000572204589844,100.18568420410156
3,FROM,text,10,100,13.190999984741211,13.46399974822998,-0.27299976348876953,97.97237396240234
4,FROM,text,10,100,14.321000099182129,13.46399974822998,0.8570003509521484,106.36511993408203
5,FROM,text,10,100,14.293999671936035,13.46399974822998,0.8299999237060547,106.16458892822266
6,FROM,text,10,100,13.604000091552734,13.46399974822998,0.1400003433227539,101.0398178100586
0,TO,text,10,100,13.826000213623047,13.826000213623047,0.0,100.0
1,TO,text,10,100,12.98799991607666,13.826000213623047,-0.8380002975463867,93.93894958496094
2,TO,text,10,100,14.069000244140625,13.826000213623047,0.24300003051757812,101.75756072998047
3,TO,text,10,100,12.906999588012695,13.826000213623047,-0.9190006256103516,93.35309600830078
4,TO,text,10,100,13.916000366210938,13.826000213623047,0.09000015258789062,100.65095520019531
5,TO,text,10,100,13.871999740600586,13.826000213623047,0.04599952697753906,100.33270263671875
6,TO,text,10,100,12.935999870300293,13.826000213623047,-0.8900003433227539,93.56285095214844
0,FROM,text,10,1000,15.456000328063965,15.456000328063965,0.0,100.0
1,FROM,text,10,1000,15.345999717712402,15.456000328063965,-0.1100006103515625,99.28829956054688
2,FROM,text,10,1000,15.972999572753906,15.456000328063965,0.5169992446899414,103.34497833251953
3,FROM,text,10,1000,15.253000259399414,15.456000328063965,-0.20300006866455078,98.68659210205078
4,FROM,text,10,1000,15.376999855041504,15.456000328063965,-0.07900047302246094,99.4888687133789
5,FROM,text,10,1000,15.687999725341797,15.456000328063965,0.23199939727783203,101.50103759765625
6,FROM,text,10,1000,15.229000091552734,15.456000328063965,-0.22700023651123047,98.53131103515625
0,TO,text,10,1000,12.979999542236328,12.979999542236328,0.0,100.0
1,TO,text,10,1000,12.913999557495117,12.979999542236328,-0.06599998474121094,99.49152374267578
2,TO,text,10,1000,12.746000289916992,12.979999542236328,-0.23399925231933594,98.19723510742188
3,TO,text,10,1000,12.88700008392334,12.979999542236328,-0.09299945831298828,99.28351593017578
4,TO,text,10,1000,12.925000190734863,12.979999542236328,-0.054999351501464844,99.57627868652344
5,TO,text,10,1000,12.961000442504883,12.979999542236328,-0.018999099731445312,99.85363006591797
6,TO,text,10,1000,13.401000022888184,12.979999542236328,0.42100048065185547,103.24346160888672
0,FROM,text,10,10000,17.261001586914062,17.261001586914062,0.0,100.0
1,FROM,text,10,10000,17.48400115966797,17.261001586914062,0.22299957275390625,101.29193115234375
2,FROM,text,10,10000,17.582000732421875,17.261001586914062,0.3209991455078125,101.85968017578125
3,FROM,text,10,10000,17.324499130249023,17.261001586914062,0.06349754333496094,100.36786651611328
4,FROM,text,10,10000,17.175498962402344,17.261001586914062,-0.08550262451171875,99.50464630126953
5,FROM,text,10,10000,17.169498443603516,17.261001586914062,-0.09150314331054688,99.46987915039062
6,FROM,text,10,10000,17.300498962402344,17.261001586914062,0.03949737548828125,100.22882080078125
0,TO,text,10,10000,14.906000137329102,14.906000137329102,0.0,100.0
1,TO,text,10,10000,15.180500030517578,14.906000137329102,0.27449989318847656,101.84154510498047
2,TO,text,10,10000,15.250999450683594,14.906000137329102,0.3449993133544922,102.31449890136719
3,TO,text,10,10000,15.044000625610352,14.906000137329102,0.13800048828125,100.9258041381836
4,TO,text,10,10000,14.910499572753906,14.906000137329102,0.0044994354248046875,100.03018188476562
5,TO,text,10,10000,14.90999984741211,14.906000137329102,0.0039997100830078125,100.0268325805664
6,TO,text,10,10000,14.881500244140625,14.906000137329102,-0.024499893188476562,99.83563995361328
0,FROM,text,10,100000,35.11399841308594,35.11399841308594,0.0,100.0
1,FROM,text,10,100000,35.29199981689453,35.11399841308594,0.17800140380859375,100.50692749023438
2,FROM,text,10,100000,35.16600036621094,35.11399841308594,0.052001953125,100.1480941772461
3,FROM,text,10,100000,35.22800064086914,35.11399841308594,0.11400222778320312,100.32466888427734
4,FROM,text,10,100000,34.93000030517578,35.11399841308594,-0.18399810791015625,99.47599792480469
5,FROM,text,10,100000,35.04800033569336,35.11399841308594,-0.06599807739257812,99.81204986572266
6,FROM,text,10,100000,35.678001403808594,35.11399841308594,0.5640029907226562,101.606201171875
0,TO,text,10,100000,33.856998443603516,33.856998443603516,0.0,100.0
1,TO,text,10,100000,33.944000244140625,33.856998443603516,0.08700180053710938,100.25696563720703
2,TO,text,10,100000,33.941001892089844,33.856998443603516,0.08400344848632812,100.24810791015625
3,TO,text,10,100000,33.91299819946289,33.856998443603516,0.055999755859375,100.1654052734375
4,TO,text,10,100000,34.06800079345703,33.856998443603516,0.21100234985351562,100.62321472167969
5,TO,text,10,100000,33.82099914550781,33.856998443603516,-0.035999298095703125,99.89366912841797
6,TO,text,10,100000,34.25299835205078,33.856998443603516,0.3959999084472656,101.16962432861328
0,FROM,text,10,1000000,212.01100158691406,212.01100158691406,0.0,100.0
1,FROM,text,10,1000000,212.14300537109375,212.01100158691406,0.1320037841796875,100.06226348876953
2,FROM,text,10,1000000,210.5030059814453,212.01100158691406,-1.50799560546875,99.2887191772461
3,FROM,text,10,1000000,213.35800170898438,212.01100158691406,1.3470001220703125,100.6353530883789
4,FROM,text,10,1000000,211.28700256347656,212.01100158691406,-0.7239990234375,99.65850830078125
5,FROM,text,10,1000000,214.52200317382812,212.01100158691406,2.5110015869140625,101.18437194824219
6,FROM,text,10,1000000,212.28199768066406,212.01100158691406,0.27099609375,100.12781524658203
0,TO,text,10,1000000,220.1840057373047,220.1840057373047,0.0,100.0
1,TO,text,10,1000000,220.8820037841797,220.1840057373047,0.697998046875,100.31700134277344
2,TO,text,10,1000000,220.06399536132812,220.1840057373047,-0.1200103759765625,99.94549560546875
3,TO,text,10,1000000,220.76800537109375,220.1840057373047,0.5839996337890625,100.26522827148438
4,TO,text,10,1000000,220.60299682617188,220.1840057373047,0.4189910888671875,100.19029235839844
5,TO,text,10,1000000,220.0989990234375,220.1840057373047,-0.0850067138671875,99.96139526367188
6,TO,text,10,1000000,223.20700073242188,220.1840057373047,3.0229949951171875,101.3729476928711
0,FROM,text,100,10,13.4399995803833,13.4399995803833,0.0,100.0
1,FROM,text,100,10,13.442000389099121,13.4399995803833,0.0020008087158203125,100.014892578125
2,FROM,text,100,10,13.32699966430664,13.4399995803833,-0.11299991607666016,99.15922546386719
3,FROM,text,100,10,13.378999710083008,13.4399995803833,-0.06099987030029297,99.54613494873047
4,FROM,text,100,10,13.085000038146973,13.4399995803833,-0.3549995422363281,97.35863494873047
5,FROM,text,100,10,13.345000267028809,13.4399995803833,-0.09499931335449219,99.29315948486328
6,FROM,text,100,10,13.380999565124512,13.4399995803833,-0.05900001525878906,99.5610122680664
0,TO,text,100,10,13.131999969482422,13.131999969482422,0.0,100.0
1,TO,text,100,10,13.03499984741211,13.131999969482422,-0.0970001220703125,99.26134490966797
2,TO,text,100,10,13.067000389099121,13.131999969482422,-0.06499958038330078,99.5050277709961
3,TO,text,100,10,13.076000213623047,13.131999969482422,-0.055999755859375,99.57356262207031
4,TO,text,100,10,12.61400032043457,13.131999969482422,-0.5179996490478516,96.0554428100586
5,TO,text,100,10,13.067999839782715,13.131999969482422,-0.06400012969970703,99.51264190673828
6,TO,text,100,10,13.123000144958496,13.131999969482422,-0.008999824523925781,99.93146514892578
0,FROM,text,100,100,13.71500015258789,13.71500015258789,0.0,100.0
1,FROM,text,100,100,13.70300006866455,13.71500015258789,-0.012000083923339844,99.91250610351562
2,FROM,text,100,100,13.753000259399414,13.71500015258789,0.03800010681152344,100.27706909179688
3,FROM,text,100,100,13.72700023651123,13.71500015258789,0.012000083923339844,100.0875015258789
4,FROM,text,100,100,13.779000282287598,13.71500015258789,0.06400012969970703,100.46664428710938
5,FROM,text,100,100,13.569999694824219,13.71500015258789,-0.14500045776367188,98.94276428222656
6,FROM,text,100,100,13.66100025177002,13.71500015258789,-0.053999900817871094,99.60626983642578
0,TO,text,100,100,13.293999671936035,13.293999671936035,0.0,100.0
1,TO,text,100,100,13.196999549865723,13.293999671936035,-0.0970001220703125,99.27033996582031
2,TO,text,100,100,13.15999984741211,13.293999671936035,-0.13399982452392578,98.99202728271484
3,TO,text,100,100,13.222000122070312,13.293999671936035,-0.07199954986572266,99.45840454101562
4,TO,text,100,100,13.13700008392334,13.293999671936035,-0.1569995880126953,98.81901550292969
5,TO,text,100,100,13.222000122070312,13.293999671936035,-0.07199954986572266,99.45840454101562
6,TO,text,100,100,13.15999984741211,13.293999671936035,-0.13399982452392578,98.99202728271484
0,FROM,text,100,1000,15.53600025177002,15.53600025177002,0.0,100.0
1,FROM,text,100,1000,15.522000312805176,15.53600025177002,-0.01399993896484375,99.9098892211914
2,FROM,text,100,1000,15.579999923706055,15.53600025177002,0.043999671936035156,100.283203125
3,FROM,text,100,1000,15.510000228881836,15.53600025177002,-0.026000022888183594,99.83264923095703
4,FROM,text,100,1000,15.562999725341797,15.53600025177002,0.026999473571777344,100.17378234863281
5,FROM,text,100,1000,15.479999542236328,15.53600025177002,-0.056000709533691406,99.63954162597656
6,FROM,text,100,1000,15.534000396728516,15.53600025177002,-0.0019998550415039062,99.98712158203125
0,TO,text,100,1000,14.543999671936035,14.543999671936035,0.0,100.0
1,TO,text,100,1000,14.631999969482422,14.543999671936035,0.08800029754638672,100.60505676269531
2,TO,text,100,1000,14.52299976348877,14.543999671936035,-0.020999908447265625,99.8556137084961
3,TO,text,100,1000,14.631999969482422,14.543999671936035,0.08800029754638672,100.60505676269531
4,TO,text,100,1000,14.850000381469727,14.543999671936035,0.3060007095336914,102.10395812988281
5,TO,text,100,1000,14.50100040435791,14.543999671936035,-0.042999267578125,99.704345703125
6,TO,text,100,1000,14.637999534606934,14.543999671936035,0.09399986267089844,100.64631652832031
0,FROM,text,100,10000,29.840499877929688,29.840499877929688,0.0,100.0
1,FROM,text,100,10000,29.83650016784668,29.840499877929688,-0.0039997100830078125,99.9865951538086
2,FROM,text,100,10000,29.79800033569336,29.840499877929688,-0.042499542236328125,99.85757446289062
3,FROM,text,100,10000,29.82149887084961,29.840499877929688,-0.019001007080078125,99.93632507324219
4,FROM,text,100,10000,29.802000045776367,29.840499877929688,-0.03849983215332031,99.87097930908203
5,FROM,text,100,10000,29.852001190185547,29.840499877929688,0.011501312255859375,100.03854370117188
6,FROM,text,100,10000,29.75149917602539,29.840499877929688,-0.08900070190429688,99.70174407958984
0,TO,text,100,10000,27.8125,27.8125,0.0,100.0
1,TO,text,100,10000,27.735000610351562,27.8125,-0.0774993896484375,99.72135162353516
2,TO,text,100,10000,27.73550033569336,27.8125,-0.07699966430664062,99.72314453125
3,TO,text,100,10000,27.73200035095215,27.8125,-0.08049964904785156,99.71056365966797
4,TO,text,100,10000,27.732999801635742,27.8125,-0.07950019836425781,99.71415710449219
5,TO,text,100,10000,27.75149917602539,27.8125,-0.061000823974609375,99.78067016601562
6,TO,text,100,10000,27.772998809814453,27.8125,-0.039501190185546875,99.85797119140625
0,FROM,text,100,100000,171.33200073242188,171.33200073242188,0.0,100.0
1,FROM,text,100,100000,171.47999572753906,171.33200073242188,0.1479949951171875,100.08638000488281
2,FROM,text,100,100000,171.14300537109375,171.33200073242188,-0.188995361328125,99.88968658447266
3,FROM,text,100,100000,171.27200317382812,171.33200073242188,-0.05999755859375,99.96498107910156
4,FROM,text,100,100000,171.1280059814453,171.33200073242188,-0.2039947509765625,99.88093566894531
5,FROM,text,100,100000,171.3990020751953,171.33200073242188,0.0670013427734375,100.03910064697266
6,FROM,text,100,100000,171.45399475097656,171.33200073242188,0.1219940185546875,100.07120513916016
0,TO,text,100,100000,158.63900756835938,158.63900756835938,0.0,100.0
1,TO,text,100,100000,158.4739990234375,158.63900756835938,-0.165008544921875,99.89598083496094
2,TO,text,100,100000,158.34300231933594,158.63900756835938,-0.2960052490234375,99.81340789794922
3,TO,text,100,100000,158.14700317382812,158.63900756835938,-0.49200439453125,99.68985748291016
4,TO,text,100,100000,158.42999267578125,158.63900756835938,-0.209014892578125,99.86824035644531
5,TO,text,100,100000,158.46800231933594,158.63900756835938,-0.1710052490234375,99.89220428466797
6,TO,text,100,100000,160.50799560546875,158.63900756835938,1.868988037109375,101.17813110351562
0,FROM,text,100,1000000,1580.9320068359375,1580.9320068359375,0.0,100.0
1,FROM,text,100,1000000,1580.906982421875,1580.9320068359375,-0.0250244140625,99.9984130859375
2,FROM,text,100,1000000,1578.1190185546875,1580.9320068359375,-2.81298828125,99.82206726074219
3,FROM,text,100,1000000,1580.8890380859375,1580.9320068359375,-0.04296875,99.99728393554688
4,FROM,text,100,1000000,1579.6090087890625,1580.9320068359375,-1.322998046875,99.91631317138672
5,FROM,text,100,1000000,1579.8330078125,1580.9320068359375,-1.0989990234375,99.93048095703125
6,FROM,text,100,1000000,1581.4139404296875,1580.9320068359375,0.48193359375,100.03047943115234
0,TO,text,100,1000000,1451.4420166015625,1451.4420166015625,0.0,100.0
1,TO,text,100,1000000,1450.489990234375,1451.4420166015625,-0.9520263671875,99.93441009521484
2,TO,text,100,1000000,1449.3790283203125,1451.4420166015625,-2.06298828125,99.85786437988281
3,TO,text,100,1000000,1448.85400390625,1451.4420166015625,-2.5880126953125,99.82169342041016
4,TO,text,100,1000000,1450.280029296875,1451.4420166015625,-1.1619873046875,99.9199447631836
5,TO,text,100,1000000,1449.51904296875,1451.4420166015625,-1.9229736328125,99.86750793457031
6,TO,text,100,1000000,1453.47802734375,1451.4420166015625,2.0360107421875,100.14027404785156

---

From: Masahiko Sawada <[email-masked]>
Date: Thu, 18 Dec 2025 15:43:07 -0800

> I hope that these numbers help to proceed this proposal.

Thank you for sharing the performance test results! I'll run the same
benchmark tests on my environment.

Looking at these results, it seems that 0001-from-binary cases and
0006-to-binary cases are slower throughout the six results?

Regards,

---

From: Masahiko Sawada <[email-masked]>
Date: Mon, 22 Jun 2026 18:06:07 -0700

Hi,

On Thu, Mar 26, 2026 at 6:36 PM Sutou Kouhei <[email-masked]> wrote:
>
> Hi,
>
> In <[email-masked]>
>   "Re: Make COPY format extendable: Extract COPY TO format implementations" on Thu, 18 Dec 2025 15:43:07 -0800,
> Good point. I didn't notice them. But I feel that it's not
> related to the patch set. Because 0001 doesn't change COPY
> FROM related code. 0001 just changes COPY TO related
> code. And 0006 just adds tests. 0006 doesn't change
> implementations.
>
>
> BTW, how to proceed this proposal? It seems that we can't
> proceed this proposal without PostgreSQL committers'
> attentions but it seems that it's difficult.

Sorry for going quiet on this for a while -- I haven't had time to
work on it until now.

After more thought, I'd like to keep the custom-format changes to the
bare minimum and not disturb the existing built-in format processing.

In particular, I've dropped the earlier rework that split
CopyToStateData / CopyFromStateData to hide built-in-specific fields
from extensions. That was my own idea, but I no longer think it pays
off: the fields it hid (raw_buf, line_buf, the input buffers, etc.)
are only ever used by the built-in text/CSV/binary parsers, and a
custom format never touches them -- so visible or not, nothing depends
on them, while splitting the struct is invasive to the existing format
processing. Touching the Copy state structs is fine in itself; it's
the hiding that wasn't worth the cost.

Instead, each state struct just gets one opaque pointer for a custom
format to keep its own state, and the existing code paths are left
alone.

Updated patches attached:

- 0001 moves CopyFromStateData and CopyToStateData to a new
copy_state.h, so extensions can implement their routines without
including the *_internal.h headers. It also drops file_fdw.c's
dependency on copyfrom_internal.h.
- 0002 introduces the registration API and the opaque per-format
pointer in both structs.
- 0003 adds a callback to validate the COPY options as a whole, called
after all options are processed.
- 0004 adds the regression tests.

I'd like to proceed in this direction barring objections. Feedback is
very welcome.

Regards,

-- 
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com
From 1684e2394e5557f94c17e39b94351a76e601e00d Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <[email-masked]>
Date: Mon, 22 Jun 2026 09:21:51 -0700
Subject: [PATCH v2 2/4] Allow extensions to register custom format to COPY TO
 and COPY FROM.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
---
 src/backend/commands/Makefile     |   1 +
 src/backend/commands/copy.c       |  97 ++++++++++++++++++++--
 src/backend/commands/copyapi.c    | 131 ++++++++++++++++++++++++++++++
 src/backend/commands/copyfrom.c   |   4 +-
 src/backend/commands/copyto.c     |   4 +-
 src/backend/commands/meson.build  |   1 +
 src/include/commands/copy.h       |  19 +++++
 src/include/commands/copy_state.h |   6 ++
 src/include/commands/copyapi.h    |  37 +++++++++
 src/tools/pgindent/typedefs.list  |   1 +
 10 files changed, 290 insertions(+), 11 deletions(-)
 create mode 100644 src/backend/commands/copyapi.c

diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index 5b9d084977e..17b7aa08b55 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -23,6 +23,7 @@ OBJS = \
 	constraint.o \
 	conversioncmds.o \
 	copy.o \
+	copyapi.o \
 	copyfrom.o \
 	copyfromparse.o \
 	copyto.o \
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 003b70852bb..2fdba026ee0 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -23,6 +23,7 @@
 #include "access/xact.h"
 #include "catalog/pg_authid.h"
 #include "commands/copy.h"
+#include "commands/copyapi.h"
 #include "commands/defrem.h"
 #include "executor/executor.h"
 #include "mb/pg_wchar.h"
@@ -592,6 +593,14 @@ ProcessCopyOptions(ParseState *pstate,
 	bool		force_array_specified = false;
 	ListCell   *option;
 
+	/*
+	 * Options not recognized by core are collected here and, once the format
+	 * is known, either handed to a custom format's option parser or rejected.
+	 */
+	List	   *deferred_options = NIL;
+	ProcessOneOptionFn custom_process_option_fn = NULL;
+	char	   *custom_format_name = NULL;
+
 	/* Support external use for option sanity checking */
 	if (opts_out == NULL)
 		opts_out = palloc0_object(CopyFormatOptions);
@@ -620,6 +629,13 @@ ProcessCopyOptions(ParseState *pstate,
 				opts_out->format = COPY_FORMAT_BINARY;
 			else if (strcmp(fmt, "json") == 0)
 				opts_out->format = COPY_FORMAT_JSON;
+			else if (GetCopyCustomFormatRoutines(fmt, &opts_out->to_routine,
+												 &opts_out->from_routine,
+												 &custom_process_option_fn))
+			{
+				opts_out->format = COPY_FORMAT_CUSTOM;
+				custom_format_name = fmt;
+			}
 			else
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -775,11 +791,54 @@ ProcessCopyOptions(ParseState *pstate,
 			opts_out->reject_limit = defGetCopyRejectLimitOption(defel);
 		}
 		else
+		{
+			/*
+			 * Not a core option.  Defer the check to after the loop as it may
+			 * belong to a custom format whose "format" option has not been
+			 * seen yet.
+			 */
+			deferred_options = lappend(deferred_options, defel);
+		}
+	}
+
+	/*
+	 * Now that the format and every option have been seen, resolve the
+	 * deferred options.
+	 */
+	if (deferred_options != NIL)
+	{
+		/*
+		 * For a custom format, they belong to the handler; for any built-in
+		 * (including the default) an unrecognized option is an error,
+		 * preserving the historical behavior relied on by external callers
+		 * such as file_fdw.
+		 */
+		if (opts_out->format != COPY_FORMAT_CUSTOM || custom_process_option_fn == NULL)
+		{
+			DefElem    *defel = linitial_node(DefElem, deferred_options);
+
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
 					 errmsg("option \"%s\" not recognized",
 							defel->defname),
 					 parser_errposition(pstate, defel->location)));
+		}
+
+		/*
+		 * Hand each option core did not recognize to the format's per-option
+		 * callback. Anything the format does not claim (or any option at all
+		 * if it has no callback) is an error, so an unrecognized option
+		 * always fails here.
+		 */
+		foreach_node(DefElem, opt, deferred_options)
+		{
+			if (!custom_process_option_fn(opts_out, is_from, opt))
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("COPY format \"%s\" does not accept option \"%s\"",
+								custom_format_name, opt->defname),
+						 parser_errposition(pstate, opt->location)));
+		}
 	}
 
 	/*
@@ -869,7 +928,7 @@ ProcessCopyOptions(ParseState *pstate,
 	 * future-proofing.  Likewise we disallow all digits though only octal
 	 * digits are actually dangerous.
 	 */
-	if (opts_out->format != COPY_FORMAT_CSV &&
+	if (CopyFormatBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_CSV &&
 		strchr("\\.abcdefghijklmnopqrstuvwxyz0123456789",
 			   opts_out->delim[0]) != NULL)
 		ereport(ERROR,
@@ -888,7 +947,8 @@ ProcessCopyOptions(ParseState *pstate,
 				: errmsg("cannot specify %s in JSON mode", "HEADER"));
 
 	/* Check quote */
-	if (opts_out->format != COPY_FORMAT_CSV && opts_out->quote != NULL)
+	if (CopyFormatBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_CSV &&
+		opts_out->quote != NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -905,7 +965,8 @@ ProcessCopyOptions(ParseState *pstate,
 				 errmsg("COPY delimiter and quote must be different")));
 
 	/* Check escape */
-	if (opts_out->format != COPY_FORMAT_CSV && opts_out->escape != NULL)
+	if (CopyFormatBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_CSV &&
+		opts_out->escape != NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -917,7 +978,8 @@ ProcessCopyOptions(ParseState *pstate,
 				 errmsg("COPY escape must be a single one-byte character")));
 
 	/* Check force_quote */
-	if (opts_out->format != COPY_FORMAT_CSV && (opts_out->force_quote || opts_out->force_quote_all))
+	if (CopyFormatBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_CSV &&
+		(opts_out->force_quote || opts_out->force_quote_all))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -931,8 +993,8 @@ ProcessCopyOptions(ParseState *pstate,
 						"COPY FROM")));
 
 	/* Check force_notnull */
-	if (opts_out->format != COPY_FORMAT_CSV && (opts_out->force_notnull != NIL ||
-												opts_out->force_notnull_all))
+	if (CopyFormatBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_CSV &&
+		(opts_out->force_notnull != NIL || opts_out->force_notnull_all))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -947,8 +1009,8 @@ ProcessCopyOptions(ParseState *pstate,
 						"COPY TO")));
 
 	/* Check force_null */
-	if (opts_out->format != COPY_FORMAT_CSV && (opts_out->force_null != NIL ||
-												opts_out->force_null_all))
+	if (CopyFormatBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_CSV &&
+		(opts_out->force_null != NIL || opts_out->force_null_all))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -995,7 +1057,8 @@ ProcessCopyOptions(ParseState *pstate,
 				errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				errmsg("COPY %s is not supported for %s", "FORMAT JSON", "COPY FROM"));
 
-	if (opts_out->format != COPY_FORMAT_JSON && opts_out->force_array)
+	if (CopyFormatBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_JSON &&
+		opts_out->force_array)
 		ereport(ERROR,
 				errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				errmsg("COPY %s can only be used with JSON mode", "FORCE_ARRAY"));
@@ -1048,6 +1111,22 @@ ProcessCopyOptions(ParseState *pstate,
 		 * ON_ERROR, third is the value of the COPY option, e.g. IGNORE */
 				 errmsg("COPY %s requires %s to be set to %s",
 						"REJECT_LIMIT", "ON_ERROR", "IGNORE")));
+
+	/* Check custom format routines */
+	if (opts_out->format == COPY_FORMAT_CUSTOM)
+	{
+		if (is_from && opts_out->from_routine == NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("COPY format \"%s\" cannot be used with COPY FROM",
+							custom_format_name)));
+
+		if (!is_from && opts_out->to_routine == NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("COPY format \"%s\" cannot be used with COPY TO",
+							custom_format_name)));
+	}
 }
 
 /*
diff --git a/src/backend/commands/copyapi.c b/src/backend/commands/copyapi.c
new file mode 100644
index 00000000000..168efbcf30b
--- /dev/null
+++ b/src/backend/commands/copyapi.c
@@ -0,0 +1,131 @@
+/*-------------------------------------------------------------------------
+ *
+ * copyapi.c
+ *	  Registry for pluggable COPY TO/FROM format handlers.
+ *
+ * The built-in formats (text, csv, binary, json) are dispatched directly by
+ * the COPY engine. Extensions can provide additional formats by registering
+ * a CopyToRoutine and/or CopyFromRoutine under a name from their _PG_init();
+ * ProcessCopyOptions() then resolves "COPY ... (FORMAT 'name')" against this
+ * registry.
+ *
+ * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  src/backend/commands/copyapi.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "commands/copyapi.h"
+#include "utils/memutils.h"
+
+typedef struct CopyCustomFormatEntry
+{
+	const char *name;			/* constant string; never freed (see below) */
+	const CopyToRoutine *to_routine;
+	const CopyFromRoutine *from_routine;
+	ProcessOneOptionFn option_fn;
+} CopyCustomFormatEntry;
+
+static CopyCustomFormatEntry *CopyCustomFormatArray = NULL;
+static int	CopyCustomFormatsAssigned = 0;
+static int	CopyCustomFormatsAllocated = 0;
+
+/* Is 'name' one of the built-in format keywords? */
+static bool
+is_builtin_copy_format(const char *name)
+{
+	return (strcmp(name, "text") == 0 ||
+			strcmp(name, "csv") == 0 ||
+			strcmp(name, "binary") == 0 ||
+			strcmp(name, "json") == 0);
+}
+
+/*
+ * Register a custom COPY format. Intended to be called from an extension's
+ * _PG_init(). Either routine may be NULL if the format does not support that
+ * direction (but not both).
+ *
+ * 'option_fn' may also be NULL if the format takes no format-specific options.
+ *
+ * 'name' is assumed to be a constant string or allocated in storage that will
+ * never be freed; it is stored by reference.
+ */
+void
+RegisterCopyCustomFormat(const char *name, const CopyToRoutine *to,
+						 const CopyFromRoutine *from, ProcessOneOptionFn option_fn)
+{
+	Assert(name != NULL && name[0] != '\0');
+
+	/* Must support at least one direction */
+	Assert(to != NULL || from != NULL);
+
+	Assert(to == NULL ||
+		   (to->CopyToStart != NULL && to->CopyToOneRow != NULL &&
+			to->CopyToEnd != NULL));
+	Assert(from == NULL ||
+		   (from->CopyFromStart != NULL && from->CopyFromOneRow != NULL &&
+			from->CopyFromEnd != NULL));
+
+	/* Check if it's already used by built-in format names */
+	if (is_builtin_copy_format(name))
+		elog(ERROR, "COPY format \"%s\" is a built-in format name", name);
+
+	/* Reject a duplicate registration. */
+	for (int i = 0; i < CopyCustomFormatsAssigned; i++)
+	{
+		if (strcmp(CopyCustomFormatArray[i].name, name) == 0)
+			elog(ERROR, "COPY format \"%s\" is already registered", name);
+	}
+
+	/* Create the array on first use; it must outlive the current context. */
+	if (CopyCustomFormatArray == NULL)
+	{
+		CopyCustomFormatsAllocated = 16;
+		CopyCustomFormatArray = (CopyCustomFormatEntry *)
+			MemoryContextAlloc(TopMemoryContext,
+							   CopyCustomFormatsAllocated * sizeof(CopyCustomFormatEntry));
+	}
+
+	/* Expand if full. */
+	if (CopyCustomFormatsAssigned >= CopyCustomFormatsAllocated)
+	{
+		CopyCustomFormatsAllocated *= 2;
+		CopyCustomFormatArray = (CopyCustomFormatEntry *)
+			repalloc_array(CopyCustomFormatArray, CopyCustomFormatEntry, CopyCustomFormatsAllocated);
+	}
+
+	CopyCustomFormatArray[CopyCustomFormatsAssigned].name = name;
+	CopyCustomFormatArray[CopyCustomFormatsAssigned].to_routine = to;
+	CopyCustomFormatArray[CopyCustomFormatsAssigned].from_routine = from;
+	CopyCustomFormatArray[CopyCustomFormatsAssigned].option_fn = option_fn;
+	CopyCustomFormatsAssigned++;
+}
+
+/*
+ * Look up a previously registered custom format. Returns false if 'name' is
+ * not registered. Out-parameters may be NULL if not wanted.
+ */
+bool
+GetCopyCustomFormatRoutines(const char *name, const CopyToRoutine **to,
+							const CopyFromRoutine **from, ProcessOneOptionFn * option_fn)
+{
+	for (int i = 0; i < CopyCustomFormatsAssigned; i++)
+	{
+		if (strcmp(CopyCustomFormatArray[i].name, name) == 0)
+		{
+			if (to)
+				*to = CopyCustomFormatArray[i].to_routine;
+			if (from)
+				*from = CopyCustomFormatArray[i].from_routine;
+			if (option_fn)
+				*option_fn = CopyCustomFormatArray[i].option_fn;
+
+			return true;
+		}
+	}
+	return false;
+}
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index 2c57b32f4de..69ec94c9ec1 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -158,7 +158,9 @@ static const CopyFromRoutine CopyFromRoutineBinary = {
 static const CopyFromRoutine *
 CopyFromGetRoutine(const CopyFormatOptions *opts)
 {
-	if (opts->format == COPY_FORMAT_CSV)
+	if (opts->format == COPY_FORMAT_CUSTOM)
+		return opts->from_routine;
+	else if (opts->format == COPY_FORMAT_CSV)
 		return &CopyFromRoutineCSV;
 	else if (opts->format == COPY_FORMAT_BINARY)
 		return &CopyFromRoutineBinary;
diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index ef2038c9a5d..f897f23737f 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -130,7 +130,9 @@ static const CopyToRoutine CopyToRoutineBinary = {
 static const CopyToRoutine *
 CopyToGetRoutine(const CopyFormatOptions *opts)
 {
-	if (opts->format == COPY_FORMAT_CSV)
+	if (opts->format == COPY_FORMAT_CUSTOM)
+		return opts->to_routine;
+	else if (opts->format == COPY_FORMAT_CSV)
 		return &CopyToRoutineCSV;
 	else if (opts->format == COPY_FORMAT_BINARY)
 		return &CopyToRoutineBinary;
diff --git a/src/backend/commands/meson.build b/src/backend/commands/meson.build
index 9f258d566eb..d98273da67e 100644
--- a/src/backend/commands/meson.build
+++ b/src/backend/commands/meson.build
@@ -11,6 +11,7 @@ backend_sources += files(
   'constraint.c',
   'conversioncmds.c',
   'copy.c',
+  'copyapi.c',
   'copyfrom.c',
   'copyfromparse.c',
   'copyto.c',
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index 5e710efff5b..9c40ca4ba09 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -58,7 +58,16 @@ typedef enum CopyFormat
 	COPY_FORMAT_BINARY,
 	COPY_FORMAT_CSV,
 	COPY_FORMAT_JSON,
+	COPY_FORMAT_CUSTOM,			/* format provided by an extension */
 } CopyFormat;
+#define CopyFormatBuiltins(format) ((format) != COPY_FORMAT_CUSTOM)
+
+/*
+ * Full definitions live in commands/copyapi.h, which includes this header;
+ * CopyFormatOptions only needs to hold pointers to the resolved routines.
+ */
+struct CopyToRoutine;
+struct CopyFromRoutine;
 
 /*
  * A struct to hold COPY options, in a parsed form. All of these are related
@@ -97,6 +106,16 @@ typedef struct CopyFormatOptions
 	CopyLogVerbosityChoice log_verbosity;	/* verbosity of logged messages */
 	int64		reject_limit;	/* maximum tolerable number of errors */
 	List	   *convert_select; /* list of column names (can be NIL) */
+
+	/*
+	 * Resolved handler for a custom format. The directoin not in use may be
+	 * NULL. For built-in formats these are unused.
+	 */
+	const struct CopyToRoutine *to_routine;
+	const struct CopyFromRoutine *from_routine;
+
+	/* Custom format private option data */
+	void	   *format_private_opts;
 } CopyFormatOptions;
 
 /* These are defined in copy_state.h */
diff --git a/src/include/commands/copy_state.h b/src/include/commands/copy_state.h
index 52cbf5067eb..6c5defbf4ee 100644
--- a/src/include/commands/copy_state.h
+++ b/src/include/commands/copy_state.h
@@ -178,6 +178,9 @@ typedef struct CopyFromStateData
 #define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
 
 	uint64		bytes_processed;	/* number of bytes processed so far */
+
+	/* Custom format private data to store the state */
+	void	   *format_private;
 } CopyFromStateData;
 
 /*
@@ -248,6 +251,9 @@ typedef struct CopyToStateData
 	FmgrInfo   *out_functions;	/* lookup info for output functions */
 	MemoryContext rowcontext;	/* per-row evaluation context */
 	uint64		bytes_processed;	/* number of bytes processed so far */
+
+	/* Custom format private data to store the state */
+	void	   *format_private;
 } CopyToStateData;
 
 #endif							/* COPY_STATE_H */
diff --git a/src/include/commands/copyapi.h b/src/include/commands/copyapi.h
index 398e7a78bb3..8eb5fe9c7dc 100644
--- a/src/include/commands/copyapi.h
+++ b/src/include/commands/copyapi.h
@@ -14,6 +14,7 @@
 #ifndef COPYAPI_H
 #define COPYAPI_H
 
+#include "commands/copy_state.h"
 #include "commands/copy.h"
 
 /*
@@ -102,4 +103,40 @@ typedef struct CopyFromRoutine
 	void		(*CopyFromEnd) (CopyFromState cstate);
 } CopyFromRoutine;
 
+/*
+ * Optional callback to process one format-specific COPY option. Invoked
+ * from ProcessCopyOptions() once per option that core did not recognize, after
+ * every core option has been parsed (so 'opts' is fully populated).
+ *
+ * Returns true if the option belongs to the format and is valid. Returns false
+ * if the option is not one the format recognizes, in which case core raises the
+ * "not accepted" error; thus an unrecognized option always errors, whether or
+ * not the format supplies this callback. For a recognized option with an invalid
+ * value, the callback should ereport() itself.
+ *
+ * 'pstate' may be NULL (e.g. when options are checked outside a real COPY, as
+ * file_fdw does); parser_errposition(pstate, ...) tolerates NULL.
+ */
+typedef bool (*ProcessOneOptionFn) (CopyFormatOptions *opts, bool is_from,
+									DefElem *option);
+
+/*
+ * Register a COPY format under 'name', mapping it to its TO and/or FROM
+ * routines and optional option/validation callbacks. Intended to be called
+ * from an extension's _PG_init(). Either routine may be NULL if the format
+ * does not support that direction (but not both). Errors if 'name' collides
+ * with a built-in format or one already registered.
+ */
+extern void RegisterCopyCustomFormat(const char *name, const CopyToRoutine *to,
+									 const CopyFromRoutine *from,
+									 ProcessOneOptionFn option_fn);
+
+/*
+ * Look up a previously registered custom format. Returns false if 'name' is
+ * not registered. Out-parameters may be NULL if not wanted.
+ */
+extern bool GetCopyCustomFormatRoutines(const char *name, const CopyToRoutine **to,
+										const CopyFromRoutine **from,
+										ProcessOneOptionFn * option_fn);
+
 #endif							/* COPYAPI_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 1969d467c1d..5263710e451 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -540,6 +540,7 @@ ConvProcInfo
 ConversionLocation
 ConvertRowtypeExpr
 CookedConstraint
+CopyCustomFormatEntry
 CopyDest
 CopyFormat
 CopyFormatOptions
-- 
2.54.0

From d31d8cef68d10cb1817446af9a1e492ce88808e9 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <[email-masked]>
Date: Mon, 22 Jun 2026 13:14:31 -0700
Subject: [PATCH v2 4/4] Add test module for COPY custom format.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch-through:
---
 src/test/modules/Makefile                     |   1 +
 src/test/modules/meson.build                  |   1 +
 .../modules/test_copy_custom_format/Makefile  |  20 +++
 .../expected/test_copy_custom_format.out      | 105 +++++++++++
 .../test_copy_custom_format/meson.build       |  32 ++++
 .../sql/test_copy_custom_format.sql           |  32 ++++
 .../test_copy_custom_format.c                 | 169 ++++++++++++++++++
 src/tools/pgindent/typedefs.list              |   1 +
 8 files changed, 361 insertions(+)
 create mode 100644 src/test/modules/test_copy_custom_format/Makefile
 create mode 100644 src/test/modules/test_copy_custom_format/expected/test_copy_custom_format.out
 create mode 100644 src/test/modules/test_copy_custom_format/meson.build
 create mode 100644 src/test/modules/test_copy_custom_format/sql/test_copy_custom_format.sql
 create mode 100644 src/test/modules/test_copy_custom_format/test_copy_custom_format.c

diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile
index 0a74ab5c86f..6dcb66174f5 100644
--- a/src/test/modules/Makefile
+++ b/src/test/modules/Makefile
@@ -23,6 +23,7 @@ SUBDIRS = \
 		  test_cloexec \
 		  test_checksums \
 		  test_copy_callbacks \
+		  test_copy_custom_format \
 		  test_custom_rmgrs \
 		  test_custom_stats \
 		  test_custom_types \
diff --git a/src/test/modules/meson.build b/src/test/modules/meson.build
index 4bca42bb370..adfa413fe58 100644
--- a/src/test/modules/meson.build
+++ b/src/test/modules/meson.build
@@ -23,6 +23,7 @@ subdir('test_bloomfilter')
 subdir('test_cloexec')
 subdir('test_checksums')
 subdir('test_copy_callbacks')
+subdir('test_copy_custom_format')
 subdir('test_cplusplusext')
 subdir('test_custom_rmgrs')
 subdir('test_custom_stats')
diff --git a/src/test/modules/test_copy_custom_format/Makefile b/src/test/modules/test_copy_custom_format/Makefile
new file mode 100644
index 00000000000..68a2a04ff09
--- /dev/null
+++ b/src/test/modules/test_copy_custom_format/Makefile
@@ -0,0 +1,20 @@
+# src/test/modules/test_copy_custom_format/Makefile
+
+MODULE_big = test_copy_custom_format
+OBJS = \
+	$(WIN32RES) \
+	test_copy_custom_format.o
+PGFILEDESC = "test_copy_custom_format - test custom COPY FORMAT"
+
+REGRESS = test_copy_custom_format
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_copy_custom_format
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/test_copy_custom_format/expected/test_copy_custom_format.out b/src/test/modules/test_copy_custom_format/expected/test_copy_custom_format.out
new file mode 100644
index 00000000000..817ca3fa60f
--- /dev/null
+++ b/src/test/modules/test_copy_custom_format/expected/test_copy_custom_format.out
@@ -0,0 +1,105 @@
+LOAD 'test_copy_custom_format';
+CREATE TABLE copy_data (a smallint, b integer, c bigint);
+INSERT INTO copy_data VALUES (1,2,3),(12,34,56),(123,456,789);
+COPY copy_data TO stdout WITH (format 'test_format');          -- Start, OutFunc x3, OneRow x3, End
+NOTICE:  CopyToOutFunc: attribute: smallint
+NOTICE:  CopyToOutFunc: attribute: integer
+NOTICE:  CopyToOutFunc: attribute: bigint
+NOTICE:  CopyToStart: the number of attributes of table: 3, the number of attributes to output: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToEnd
+COPY copy_data FROM stdin WITH (format 'test_format');         -- InFunc x3, Start, OneRow, End
+NOTICE:  CopyFromInFunc: attribute: smallint
+NOTICE:  CopyFromInFunc: attribute: integer
+NOTICE:  CopyFromInFunc: attribute: bigint
+NOTICE:  CopyFromStart: the number of attributes of table: 3, the number of attributes to input: 3
+NOTICE:  CopyFromOneRow
+NOTICE:  CopyFromEnd
+COPY copy_data (a, b) TO stdout WITH (format 'test_format');   -- Start: natts 2
+NOTICE:  CopyToOutFunc: attribute: smallint
+NOTICE:  CopyToOutFunc: attribute: integer
+NOTICE:  CopyToStart: the number of attributes of table: 3, the number of attributes to output: 2
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToEnd
+COPY (SELECT a FROM copy_data) TO stdout WITH (format 'test_format'); -- Start: natts 1
+NOTICE:  CopyToOutFunc: attribute: smallint
+NOTICE:  CopyToStart: the number of attributes of table: 1, the number of attributes to output: 1
+NOTICE:  CopyToOneRow: the number of valid values: 1
+NOTICE:  CopyToOneRow: the number of valid values: 1
+NOTICE:  CopyToOneRow: the number of valid values: 1
+NOTICE:  CopyToEnd
+COPY copy_data TO stdout WITH (format 'nonexistent');          -- ERROR: not recognized
+ERROR:  COPY format "nonexistent" not recognized
+LINE 1: COPY copy_data TO stdout WITH (format 'nonexistent');
+                                       ^
+COPY copy_data TO stdout WITH (format 'text', format 'csv');   -- ERROR: conflicting
+ERROR:  conflicting or redundant options
+LINE 1: COPY copy_data TO stdout WITH (format 'text', format 'csv');
+                                                      ^
+COPY copy_data TO stdout WITH (format 'test_format', bogus 1); -- ERROR
+ERROR:  COPY format "test_format" does not accept option "bogus"
+LINE 1: ...PY copy_data TO stdout WITH (format 'test_format', bogus 1);
+                                                              ^
+COPY copy_data TO stdout WITH (format 'test_format', max_attributes 5); -- OK
+NOTICE:  CopyToOutFunc: attribute: smallint
+NOTICE:  CopyToOutFunc: attribute: integer
+NOTICE:  CopyToOutFunc: attribute: bigint
+NOTICE:  CopyToStart: the number of attributes of table: 3, the number of attributes to output: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToEnd
+COPY copy_data TO stdout WITH (format 'test_format', max_attributes 3); -- OK
+NOTICE:  CopyToOutFunc: attribute: smallint
+NOTICE:  CopyToOutFunc: attribute: integer
+NOTICE:  CopyToOutFunc: attribute: bigint
+NOTICE:  CopyToStart: the number of attributes of table: 3, the number of attributes to output: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToEnd
+COPY copy_data TO stdout WITH (format 'test_format', max_attributes 2); -- ERROR: 3 columns exceeds 2
+NOTICE:  CopyToOutFunc: attribute: smallint
+NOTICE:  CopyToOutFunc: attribute: integer
+NOTICE:  CopyToOutFunc: attribute: bigint
+ERROR:  relation has 3 columns, exceeds max_attributes 2
+COPY copy_data TO stdout WITH (format 'test_format', max_attributes 0);   -- ERROR: positive
+ERROR:  "max_attributes" must be a positive integer
+COPY copy_data TO stdout WITH (format 'test_format', max_attributes -1);  -- ERROR
+ERROR:  "max_attributes" must be a positive integer
+COPY copy_data TO stdout WITH (format 'test_format', max_attributes 'x'); -- ERROR: integer required
+ERROR:  max_attributes requires an integer value
+COPY copy_data FROM stdin WITH (format 'test_format', freeze true, disallow_freeze true); -- ERROR (validate)
+ERROR:  FREEZE cannot be used with "disallow_freeze" option
+COPY copy_data FROM stdin WITH (format 'test_format', disallow_freeze true); -- OK
+NOTICE:  CopyFromInFunc: attribute: smallint
+NOTICE:  CopyFromInFunc: attribute: integer
+NOTICE:  CopyFromInFunc: attribute: bigint
+NOTICE:  CopyFromStart: the number of attributes of table: 3, the number of attributes to input: 3
+NOTICE:  CopyFromOneRow
+NOTICE:  CopyFromEnd
+-- The built-in options are handled in the same way of built-in formats.
+COPY copy_data TO stdout WITH (format 'test_format', delimiter ',');
+NOTICE:  CopyToOutFunc: attribute: smallint
+NOTICE:  CopyToOutFunc: attribute: integer
+NOTICE:  CopyToOutFunc: attribute: bigint
+NOTICE:  CopyToStart: the number of attributes of table: 3, the number of attributes to output: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToEnd
+COPY copy_data TO stdout WITH (format 'test_format', quote '"');
+NOTICE:  CopyToOutFunc: attribute: smallint
+NOTICE:  CopyToOutFunc: attribute: integer
+NOTICE:  CopyToOutFunc: attribute: bigint
+NOTICE:  CopyToStart: the number of attributes of table: 3, the number of attributes to output: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToOneRow: the number of valid values: 3
+NOTICE:  CopyToEnd
+COPY copy_data TO stdout WITH (format 'test_format', freeze true);     -- ERROR: FREEZE with COPY TO
+ERROR:  COPY FREEZE cannot be used with COPY TO
diff --git a/src/test/modules/test_copy_custom_format/meson.build b/src/test/modules/test_copy_custom_format/meson.build
new file mode 100644
index 00000000000..a231ed57649
--- /dev/null
+++ b/src/test/modules/test_copy_custom_format/meson.build
@@ -0,0 +1,32 @@
+# Copyright (c) 2025, PostgreSQL Global Development Group
+
+test_copy_custom_format_sources = files(
+'test_copy_custom_format.c',
+)
+
+if host_system == 'windows'
+  test_copy_custom_format_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'test_copy_custom_format',
+    '--FILEDESC', 'test_copy_custom_format - test custom COPY FORMAT',])
+endif
+
+test_copy_custom_format = shared_module('test_copy_custom_format',
+  test_copy_custom_format_sources,
+  kwargs: pg_test_mod_args,
+)
+test_install_libs += test_copy_custom_format
+
+tests += {
+  'name': 'test_copy_custom_format',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'test_copy_custom_format',
+    ],
+    # Disabled because these tests require
+    # "shared_preload_libraries=test_custom_copy_format", which typical
+    # runningcheck users do not have (e.g. buildfarm clients).
+    'runningcheck': false,
+  },
+}
diff --git a/src/test/modules/test_copy_custom_format/sql/test_copy_custom_format.sql b/src/test/modules/test_copy_custom_format/sql/test_copy_custom_format.sql
new file mode 100644
index 00000000000..59f58fa55a2
--- /dev/null
+++ b/src/test/modules/test_copy_custom_format/sql/test_copy_custom_format.sql
@@ -0,0 +1,32 @@
+LOAD 'test_copy_custom_format';
+
+CREATE TABLE copy_data (a smallint, b integer, c bigint);
+INSERT INTO copy_data VALUES (1,2,3),(12,34,56),(123,456,789);
+
+COPY copy_data TO stdout WITH (format 'test_format');          -- Start, OutFunc x3, OneRow x3, End
+COPY copy_data FROM stdin WITH (format 'test_format');         -- InFunc x3, Start, OneRow, End
+\.
+
+COPY copy_data (a, b) TO stdout WITH (format 'test_format');   -- Start: natts 2
+COPY (SELECT a FROM copy_data) TO stdout WITH (format 'test_format'); -- Start: natts 1
+
+COPY copy_data TO stdout WITH (format 'nonexistent');          -- ERROR: not recognized
+COPY copy_data TO stdout WITH (format 'text', format 'csv');   -- ERROR: conflicting
+
+COPY copy_data TO stdout WITH (format 'test_format', bogus 1); -- ERROR
+
+COPY copy_data TO stdout WITH (format 'test_format', max_attributes 5); -- OK
+COPY copy_data TO stdout WITH (format 'test_format', max_attributes 3); -- OK
+COPY copy_data TO stdout WITH (format 'test_format', max_attributes 2); -- ERROR: 3 columns exceeds 2
+COPY copy_data TO stdout WITH (format 'test_format', max_attributes 0);   -- ERROR: positive
+COPY copy_data TO stdout WITH (format 'test_format', max_attributes -1);  -- ERROR
+COPY copy_data TO stdout WITH (format 'test_format', max_attributes 'x'); -- ERROR: integer required
+
+COPY copy_data FROM stdin WITH (format 'test_format', freeze true, disallow_freeze true); -- ERROR (validate)
+COPY copy_data FROM stdin WITH (format 'test_format', disallow_freeze true); -- OK
+\.
+
+-- The built-in options are handled in the same way of built-in formats.
+COPY copy_data TO stdout WITH (format 'test_format', delimiter ',');
+COPY copy_data TO stdout WITH (format 'test_format', quote '"');
+COPY copy_data TO stdout WITH (format 'test_format', freeze true);     -- ERROR: FREEZE with COPY TO
diff --git a/src/test/modules/test_copy_custom_format/test_copy_custom_format.c b/src/test/modules/test_copy_custom_format/test_copy_custom_format.c
new file mode 100644
index 00000000000..ca25832fcb0
--- /dev/null
+++ b/src/test/modules/test_copy_custom_format/test_copy_custom_format.c
@@ -0,0 +1,169 @@
+/*--------------------------------------------------------------------------
+ *
+ * test_copy_custom_format.c
+ *		Code for testing custom COPY format.
+ *
+ * Portions Copyright (c) 2026, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *		src/test/modules/test_copy_custom_format/test_copy_custom_format.c
+ *
+ * -------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "commands/copy.h"
+#include "commands/copyapi.h"
+#include "commands/copy_state.h"
+#include "commands/defrem.h"
+#include "utils/builtins.h"
+
+PG_MODULE_MAGIC;
+
+typedef struct TestCopyOptions
+{
+	int			max_attributes;
+	bool		disallow_freeze;
+} TestCopyOptions;
+
+static bool
+TestCopyProcessOneOption(CopyFormatOptions *opts, bool is_from, DefElem *option)
+{
+	TestCopyOptions *t = (TestCopyOptions *) opts->format_private_opts;
+
+	if (t == NULL)
+	{
+		t = palloc0_object(TestCopyOptions);
+		opts->format_private_opts = (void *) t;
+	}
+
+	if (strcmp(option->defname, "max_attributes") == 0)
+	{
+		int			val = defGetInt32(option);
+
+		if (val < 1)
+			ereport(ERROR,
+					errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					errmsg("\"max_attributes\" must be a positive integer"));
+
+		t->max_attributes = val;
+		return true;
+	}
+	else if (strcmp(option->defname, "disallow_freeze") == 0)
+	{
+		t->disallow_freeze = defGetBoolean(option);
+		return true;
+	}
+
+	return false;
+}
+
+static void
+TestCopyValidateOptions(CopyFormatOptions *opts, bool is_from)
+{
+	TestCopyOptions *t = (TestCopyOptions *) opts->format_private_opts;
+
+	if (!t)
+		return;
+
+	if (t->disallow_freeze && opts->freeze)
+		ereport(ERROR,
+				errmsg("FREEZE cannot be used with \"disallow_freeze\" option"));
+}
+
+static void
+TestCopyFromInFunc(CopyFromState cstate, Oid atttypid, FmgrInfo *finfo, Oid *typioparam)
+{
+	ereport(NOTICE,
+			errmsg("CopyFromInFunc: attribute: %s", format_type_be(atttypid)));
+}
+
+static void
+check_max_attributes(CopyFormatOptions *opts, TupleDesc tupDesc)
+{
+	TestCopyOptions *t = (TestCopyOptions *) opts->format_private_opts;
+
+	if (t != NULL && t->max_attributes > 0 && tupDesc->natts > t->max_attributes)
+		ereport(ERROR,
+				errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				errmsg("relation has %d columns, exceeds max_attributes %d",
+					   tupDesc->natts, t->max_attributes));
+}
+
+static void
+TestCopyFromStart(CopyFromState cstate, TupleDesc tupDesc)
+{
+	check_max_attributes(&cstate->opts, tupDesc);
+
+	ereport(NOTICE,
+			errmsg("CopyFromStart: the number of attributes of table: %d, the number of attributes to input: %d",
+				   tupDesc->natts, list_length(cstate->attnumlist)));
+}
+
+static bool
+TestCopyFromOneRow(CopyFromState cstate, ExprContext *econtext, Datum *values, bool *nulls)
+{
+	ereport(NOTICE, errmsg("CopyFromOneRow"));
+
+	return false;
+}
+
+static void
+TestCopyFromEnd(CopyFromState cstate)
+{
+	ereport(NOTICE, errmsg("CopyFromEnd"));
+}
+
+static void
+TestCopyToOutFunc(CopyToState cstate, Oid atttypid, FmgrInfo *finfo)
+{
+	ereport(NOTICE, errmsg("CopyToOutFunc: attribute: %s", format_type_be(atttypid)));
+}
+
+static void
+TestCopyToStart(CopyToState cstate, TupleDesc tupDesc)
+{
+	check_max_attributes(&cstate->opts, tupDesc);
+
+	ereport(NOTICE,
+			errmsg("CopyToStart: the number of attributes of table: %d, the number of attributes to output: %d",
+				   tupDesc->natts, list_length(cstate->attnumlist)));
+}
+
+static void
+TestCopyToOneRow(CopyToState cstate, TupleTableSlot *slot)
+{
+	ereport(NOTICE, (errmsg("CopyToOneRow: the number of valid values: %u", slot->tts_nvalid)));
+}
+
+static void
+TestCopyToEnd(CopyToState cstate)
+{
+	ereport(NOTICE, (errmsg("CopyToEnd")));
+}
+
+static const CopyToRoutine TestCopyToRoutine = {
+	.CopyToOutFunc = TestCopyToOutFunc,
+	.CopyToStart = TestCopyToStart,
+	.CopyToOneRow = TestCopyToOneRow,
+	.CopyToEnd = TestCopyToEnd,
+};
+
+
+static const CopyFromRoutine TestCopyFromRoutine = {
+	.CopyFromInFunc = TestCopyFromInFunc,
+	.CopyFromStart = TestCopyFromStart,
+	.CopyFromOneRow = TestCopyFromOneRow,
+	.CopyFromEnd = TestCopyFromEnd,
+};
+
+void
+_PG_init(void)
+{
+	RegisterCopyCustomFormat("test_format",
+							 &TestCopyToRoutine,
+							 &TestCopyFromRoutine,
+							 &TestCopyProcessOneOption,
+							 &TestCopyValidateOptions);
+}
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 5263710e451..552669abc5f 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3179,6 +3179,7 @@ Tcl_Obj
 Tcl_Size
 Tcl_Time
 TempNamespaceStatus
+TestCopyOptions
 TestDSMRegistryHashEntry
 TestDSMRegistryStruct
 TestDecodingData
-- 
2.54.0

From c0e1e5986d10125b41f3fde10cdb3ba931db00b3 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <[email-masked]>
Date: Mon, 22 Jun 2026 09:23:09 -0700
Subject: [PATCH v2 3/4] Add an hook for custom COPY format option validation.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
---
 src/backend/commands/copy.c    | 13 ++++++++++++-
 src/backend/commands/copyapi.c | 10 ++++++++--
 src/include/commands/copyapi.h | 15 +++++++++++++--
 3 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 2fdba026ee0..45908d0c1e5 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -599,6 +599,7 @@ ProcessCopyOptions(ParseState *pstate,
 	 */
 	List	   *deferred_options = NIL;
 	ProcessOneOptionFn custom_process_option_fn = NULL;
+	ValidateOptionsFn custom_validate_options_fn = NULL;
 	char	   *custom_format_name = NULL;
 
 	/* Support external use for option sanity checking */
@@ -631,7 +632,8 @@ ProcessCopyOptions(ParseState *pstate,
 				opts_out->format = COPY_FORMAT_JSON;
 			else if (GetCopyCustomFormatRoutines(fmt, &opts_out->to_routine,
 												 &opts_out->from_routine,
-												 &custom_process_option_fn))
+												 &custom_process_option_fn,
+												 &custom_validate_options_fn))
 			{
 				opts_out->format = COPY_FORMAT_CUSTOM;
 				custom_format_name = fmt;
@@ -1126,6 +1128,15 @@ ProcessCopyOptions(ParseState *pstate,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("COPY format \"%s\" cannot be used with COPY TO",
 							custom_format_name)));
+
+		/*
+		 * Let the format validate its fully-parsed options as a whole.  This
+		 * runs even when no format-specific options were given, so a format
+		 * can reject incompatible core options or enforce cross-option
+		 * constraints.
+		 */
+		if (custom_validate_options_fn != NULL)
+			custom_validate_options_fn(opts_out, is_from);
 	}
 }
 
diff --git a/src/backend/commands/copyapi.c b/src/backend/commands/copyapi.c
index 168efbcf30b..0bd1cb71af2 100644
--- a/src/backend/commands/copyapi.c
+++ b/src/backend/commands/copyapi.c
@@ -28,6 +28,7 @@ typedef struct CopyCustomFormatEntry
 	const CopyToRoutine *to_routine;
 	const CopyFromRoutine *from_routine;
 	ProcessOneOptionFn option_fn;
+	ValidateOptionsFn validate_fn;
 } CopyCustomFormatEntry;
 
 static CopyCustomFormatEntry *CopyCustomFormatArray = NULL;
@@ -56,7 +57,8 @@ is_builtin_copy_format(const char *name)
  */
 void
 RegisterCopyCustomFormat(const char *name, const CopyToRoutine *to,
-						 const CopyFromRoutine *from, ProcessOneOptionFn option_fn)
+						 const CopyFromRoutine *from, ProcessOneOptionFn option_fn,
+						 ValidateOptionsFn validate_fn)
 {
 	Assert(name != NULL && name[0] != '\0');
 
@@ -102,6 +104,7 @@ RegisterCopyCustomFormat(const char *name, const CopyToRoutine *to,
 	CopyCustomFormatArray[CopyCustomFormatsAssigned].to_routine = to;
 	CopyCustomFormatArray[CopyCustomFormatsAssigned].from_routine = from;
 	CopyCustomFormatArray[CopyCustomFormatsAssigned].option_fn = option_fn;
+	CopyCustomFormatArray[CopyCustomFormatsAssigned].validate_fn = validate_fn;
 	CopyCustomFormatsAssigned++;
 }
 
@@ -111,7 +114,8 @@ RegisterCopyCustomFormat(const char *name, const CopyToRoutine *to,
  */
 bool
 GetCopyCustomFormatRoutines(const char *name, const CopyToRoutine **to,
-							const CopyFromRoutine **from, ProcessOneOptionFn * option_fn)
+							const CopyFromRoutine **from, ProcessOneOptionFn * option_fn,
+							ValidateOptionsFn * validate_fn)
 {
 	for (int i = 0; i < CopyCustomFormatsAssigned; i++)
 	{
@@ -123,6 +127,8 @@ GetCopyCustomFormatRoutines(const char *name, const CopyToRoutine **to,
 				*from = CopyCustomFormatArray[i].from_routine;
 			if (option_fn)
 				*option_fn = CopyCustomFormatArray[i].option_fn;
+			if (validate_fn)
+				*validate_fn = CopyCustomFormatArray[i].validate_fn;
 
 			return true;
 		}
diff --git a/src/include/commands/copyapi.h b/src/include/commands/copyapi.h
index 8eb5fe9c7dc..c47c89a858f 100644
--- a/src/include/commands/copyapi.h
+++ b/src/include/commands/copyapi.h
@@ -120,6 +120,15 @@ typedef struct CopyFromRoutine
 typedef bool (*ProcessOneOptionFn) (CopyFormatOptions *opts, bool is_from,
 									DefElem *option);
 
+/*
+ * Optional callback to validate a custom format's fully-parsed options as a
+ * whole. Invoked once from ProcessCopyOptions() after all options have been
+ * processed, so it can enforce cross-option constraints and reject
+ * incompatible core options. It runs even when no format-specific options were
+ * supplied. Reports problems with ereport().
+ */
+typedef void (*ValidateOptionsFn) (CopyFormatOptions *opts, bool is_from);
+
 /*
  * Register a COPY format under 'name', mapping it to its TO and/or FROM
  * routines and optional option/validation callbacks. Intended to be called
@@ -129,7 +138,8 @@ typedef bool (*ProcessOneOptionFn) (CopyFormatOptions *opts, bool is_from,
  */
 extern void RegisterCopyCustomFormat(const char *name, const CopyToRoutine *to,
 									 const CopyFromRoutine *from,
-									 ProcessOneOptionFn option_fn);
+									 ProcessOneOptionFn option_fn,
+									 ValidateOptionsFn validate_fn);
 
 /*
  * Look up a previously registered custom format. Returns false if 'name' is
@@ -137,6 +147,7 @@ extern void RegisterCopyCustomFormat(const char *name, const CopyToRoutine *to,
  */
 extern bool GetCopyCustomFormatRoutines(const char *name, const CopyToRoutine **to,
 										const CopyFromRoutine **from,
-										ProcessOneOptionFn * option_fn);
+										ProcessOneOptionFn * option_fn,
+										ValidateOptionsFn * validate_fn);
 
 #endif							/* COPYAPI_H */
-- 
2.54.0

From 47aa927d65e483331f9b2010499b4c7f0bfb562c Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <[email-masked]>
Date: Mon, 22 Jun 2026 11:50:27 -0700
Subject: [PATCH v2 1/4] Move Copy[From|To]StateData to copy_state.h.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch-through:
---
 contrib/file_fdw/file_fdw.c              |   2 +-
 src/backend/commands/copyfrom.c          |   5 +-
 src/backend/commands/copyfromparse.c     |  10 +-
 src/backend/commands/copyto.c            |  88 +-------
 src/include/commands/copy.h              |   2 +-
 src/include/commands/copy_state.h        | 253 +++++++++++++++++++++++
 src/include/commands/copyfrom_internal.h | 165 +--------------
 7 files changed, 273 insertions(+), 252 deletions(-)
 create mode 100644 src/include/commands/copy_state.h

diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c
index 33a37d832ce..d152d05b92e 100644
--- a/contrib/file_fdw/file_fdw.c
+++ b/contrib/file_fdw/file_fdw.c
@@ -22,7 +22,7 @@
 #include "catalog/pg_authid.h"
 #include "catalog/pg_foreign_table.h"
 #include "commands/copy.h"
-#include "commands/copyfrom_internal.h"
+#include "commands/copy_state.h"
 #include "commands/defrem.h"
 #include "commands/explain_format.h"
 #include "commands/explain_state.h"
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index 0087585b2c4..2c57b32f4de 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -30,6 +30,7 @@
 #include "access/xact.h"
 #include "catalog/namespace.h"
 #include "commands/copyapi.h"
+#include "commands/copy_state.h"
 #include "commands/copyfrom_internal.h"
 #include "commands/progress.h"
 #include "commands/trigger.h"
@@ -1732,7 +1733,7 @@ BeginCopyFrom(ParseState *pstate,
 							pg_encoding_to_char(GetDatabaseEncoding()))));
 	}

 
@@ -1861,7 +1862,7 @@ BeginCopyFrom(ParseState *pstate,
 	if (data_source_cb)
 	{
 		progress_vals[1] = PROGRESS_COPY_TYPE_CALLBACK;
-		cstate->copy_src = COPY_CALLBACK;
+		cstate->copy_src = COPY_SOURCE_CALLBACK;
 		cstate->data_source_cb = data_source_cb;
 	}
 	else if (pipe)
diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index 65fd5a0ab4f..0ff5db4b62d 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -184,7 +184,7 @@ ReceiveCopyBegin(CopyFromState cstate)
 	for (i = 0; i < natts; i++)
 		pq_sendint16(&buf, format); /* per-column formats */
 	pq_endmessage(&buf);
-	cstate->copy_src = COPY_FRONTEND;
+	cstate->copy_src = COPY_SOURCE_FRONTEND;
 	cstate->fe_msgbuf = makeStringInfo();
 	/* We *must* flush here to ensure FE knows it can send. */
 	pq_flush();
@@ -252,7 +252,7 @@ CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
 
 	switch (cstate->copy_src)
 	{
-		case COPY_FILE:
+		case COPY_SOURCE_FILE:
 			pgstat_report_wait_start(WAIT_EVENT_COPY_FROM_READ);
 			bytesread = fread(databuf, 1, maxread, cstate->copy_file);
 			pgstat_report_wait_end();
@@ -263,7 +263,7 @@ CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
 			if (bytesread == 0)
 				cstate->raw_reached_eof = true;
 			break;
-		case COPY_FRONTEND:
+		case COPY_SOURCE_FRONTEND:
 			while (maxread > 0 && bytesread < minread && !cstate->raw_reached_eof)
 			{
 				int			avail;
@@ -346,7 +346,7 @@ CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
 				bytesread += avail;
 			}
 			break;
-		case COPY_CALLBACK:
+		case COPY_SOURCE_CALLBACK:
 			bytesread = cstate->data_source_cb(databuf, minread, maxread);
 			break;
 	}
@@ -1259,7 +1259,7 @@ CopyReadLine(CopyFromState cstate, bool is_csv)
 		 * after \. up to the protocol end of copy data.  (XXX maybe better
 		 * not to treat \. as special?)
 		 */
-		if (cstate->copy_src == COPY_FRONTEND)
+		if (cstate->copy_src == COPY_SOURCE_FRONTEND)
 		{
 			int			inbytes;
 
diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index 6755bb698de..ef2038c9a5d 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -23,8 +23,8 @@
 #include "access/tupconvert.h"
 #include "catalog/pg_inherits.h"
 #include "commands/copyapi.h"
+#include "commands/copy_state.h"
 #include "commands/progress.h"
-#include "executor/execdesc.h"
 #include "executor/executor.h"
 #include "executor/tuptable.h"
 #include "funcapi.h"
@@ -42,76 +42,6 @@
 #include "utils/snapmgr.h"
 #include "utils/wait_event.h"
 
-/*
-	bool		json_row_delim_needed;	/* need delimiter before next row */
-	StringInfo	json_buf;		/* reusable buffer for JSON output,
-								 * initialized in BeginCopyTo */
-	TupleDesc	tupDesc;		/* Descriptor for JSON output; for a column
-								 * list this is a projected descriptor */
-	Datum	   *json_projvalues;	/* pre-allocated projection values, or
-									 * NULL */
-	bool	   *json_projnulls; /* pre-allocated projection nulls, or NULL */
-	List	   *partitions;		/* OID list of partitions to copy data from */
@@ -559,7 +489,7 @@ SendCopyBegin(CopyToState cstate)
 	}
 
 	pq_endmessage(&buf);
 
 static void
@@ -606,7 +536,7 @@ CopySendEndOfRow(CopyToState cstate)
 
 	switch (cstate->copy_dest)
 	{
-		case COPY_FILE:
+		case COPY_DEST_FILE:
 			pgstat_report_wait_start(WAIT_EVENT_COPY_TO_WRITE);
 			if (fwrite(fe_msgbuf->data, fe_msgbuf->len, 1,
 					   cstate->copy_file) != 1 ||
@@ -642,11 +572,11 @@ CopySendEndOfRow(CopyToState cstate)
 			}
 			pgstat_report_wait_end();
 			break;
-		case COPY_FRONTEND:
+		case COPY_DEST_FRONTEND:
 			/* Dump the accumulated row as one CopyData message */
 			(void) pq_putmessage(PqMsg_CopyData, fe_msgbuf->data, fe_msgbuf->len);
 			break;
-		case COPY_CALLBACK:
+		case COPY_DEST_CALLBACK:
 			cstate->data_dest_cb(fe_msgbuf->data, fe_msgbuf->len);
 			break;
 	}
@@ -667,7 +597,7 @@ CopySendTextLikeEndOfRow(CopyToState cstate)
 {
 	switch (cstate->copy_dest)
 	{
-		case COPY_FILE:
+		case COPY_DEST_FILE:
 			/* Default line termination depends on platform */
 #ifndef WIN32
 			CopySendChar(cstate, '\n');
@@ -675,7 +605,7 @@ CopySendTextLikeEndOfRow(CopyToState cstate)
 			CopySendString(cstate, "\r\n");
 #endif
 			break;
-		case COPY_FRONTEND:
+		case COPY_DEST_FRONTEND:
 			/* The FE/BE protocol uses \n as newline for all platforms */
 			CopySendChar(cstate, '\n');
 			break;
@@ -1135,12 +1065,12 @@ BeginCopyTo(ParseState *pstate,
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);

 	if (data_dest_cb)
 	{
index abecfe51098..5e710efff5b 100644
@@ -99,7 +99,7 @@ typedef struct CopyFormatOptions
 
-/* These are private in commands/copy[from|to].c */
+/* These are defined in copy_state.h */
 typedef struct CopyFromStateData *CopyFromState;
 typedef struct CopyToStateData *CopyToState;
 
diff --git a/src/include/commands/copy_state.h b/src/include/commands/copy_state.h
new file mode 100644
index 00000000000..52cbf5067eb
--- /dev/null
+++ b/src/include/commands/copy_state.h
@@ -0,0 +1,253 @@
+/*-------------------------------------------------------------------------
+ *
+ * copy_state.h
+ *	  prototypes for COPY TO/COPY FROM execution state.
+ *
+ * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994-5, Regents of the University of California
+ *
+ * src/include/commands/copy_state.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef COPY_STATE_H
+#define COPY_STATE_H
+
+#include "commands/copy.h"
+#include "commands/trigger.h"
+#include "executor/execdesc.h"
+#include "nodes/miscnodes.h"
+
+/*
+ * Represents the different source cases we need to worry about at
+ * the bottom level
+ */
+typedef enum CopySource
+{
+	COPY_SOURCE_FILE,			/* from file (or a piped program) */
+	COPY_SOURCE_FRONTEND,		/* from frontend */
+	COPY_SOURCE_CALLBACK,		/* from callback function */
+} CopySource;
+
+/*
+ *	Represents the end-of-line terminator type of the input
+ */
+typedef enum EolType
+{
+	EOL_UNKNOWN,
+	EOL_NL,
+	EOL_CR,
+	EOL_CRNL,
+} EolType;
+
+/*
+ * This struct contains all the state variables used throughout a COPY FROM
+ * operation.
+ */
+typedef struct CopyFromStateData
+{
+	/* format routine */
+	const struct CopyFromRoutine *routine;
+
+	/* low-level state data */
+	CopySource	copy_src;		/* type of copy source */
+	FILE	   *copy_file;		/* used if copy_src == COPY_SOURCE_FILE */
+	StringInfo	fe_msgbuf;		/* used if copy_src == COPY_SOURCE_FRONTEND */
+
+	EolType		eol_type;		/* EOL type of input */
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	Oid			conversion_proc;	/* encoding conversion function */
+
+	/* parameters from the COPY command */
+	Relation	rel;			/* relation to copy from */
+	List	   *attnumlist;		/* integer list of attnums to copy */
+	char	   *filename;		/* filename, or NULL for STDIN */
+	bool		is_program;		/* is 'filename' a program to popen? */
+	copy_data_source_cb data_source_cb; /* function for reading data */
+
+	CopyFormatOptions opts;
+	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
+	Node	   *whereClause;	/* WHERE condition (or NULL) */
+
+	/* these are just for error messages, see CopyFromErrorCallback */
+	const char *cur_relname;	/* table name for error messages */
+	uint64		cur_lineno;		/* line number for error messages */
+	const char *cur_attname;	/* current att for error messages */
+	const char *cur_attval;		/* current att value for error messages */
+	bool		relname_only;	/* don't output line number, att, etc. */
+
+	/*
+	 * Working state
+	 */
+	MemoryContext copycontext;	/* per-copy execution context */
+
+	AttrNumber	num_defaults;	/* count of att that are missing and have
+								 * default value */
+	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
+	Oid		   *typioparams;	/* array of element types for in_functions */
+	ErrorSaveContext *escontext;	/* soft error trapped during in_functions
+									 * execution */
+	uint64		num_errors;		/* total number of rows which contained soft
+								 * errors */
+	int		   *defmap;			/* array of default att numbers related to
+								 * missing att */
+	ExprState **defexprs;		/* array of default att expressions for all
+								 * att */
+	bool	   *defaults;		/* if DEFAULT marker was found for
+								 * corresponding att */
+	bool		simd_enabled;	/* use SIMD to scan for special chars? */
+
+	/*
+	 * True if the corresponding attribute's is a constrained domain. This
+	 * will be populated only when ON_ERROR is SET_NULL, otherwise NULL.
+	 */
+	bool	   *domain_with_constraint;
+
+	bool		volatile_defexprs;	/* is any of defexprs volatile? */
+	List	   *range_table;	/* single element list of RangeTblEntry */
+	List	   *rteperminfos;	/* single element list of RTEPermissionInfo */
+	ExprState  *qualexpr;
+
+	TransitionCaptureState *transition_capture;
+
+	/*
+	 * These variables are used to reduce overhead in COPY FROM.
+	 *
+	 * attribute_buf holds the separated, de-escaped text for each field of
+	 * the current line.  The CopyReadAttributes functions return arrays of
+	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
+	 * the buffer on each cycle.
+	 *
+	 * In binary COPY FROM, attribute_buf holds the binary data for the
+	 * current field, but the usage is otherwise similar.
+	 */
+	StringInfoData attribute_buf;
+
+	/* field raw data pointers found by COPY FROM */
+
+	int			max_fields;
+	char	  **raw_fields;
+
+	/*
+	 * Similarly, line_buf holds the whole input line being processed. The
+	 * input cycle is first to read the whole line into line_buf, and then
+	 * extract the individual attribute fields into attribute_buf.  line_buf
+	 * is preserved unmodified so that we can display it in error messages if
+	 * appropriate.  (In binary mode, line_buf is not used.)
+	 */
+	StringInfoData line_buf;
+	bool		line_buf_valid; /* contains the row being processed? */
+
+	/*
+	 * input_buf holds input data, already converted to database encoding.
+	 *
+	 * In text mode, CopyReadLine parses this data sufficiently to locate line
+	 * boundaries, then transfers the data to line_buf. We guarantee that
+	 * there is a \0 at input_buf[input_buf_len] at all times.  (In binary
+	 * mode, input_buf is not used.)
+	 *
+	 * If encoding conversion is not required, input_buf is not a separate
+	 * buffer but points directly to raw_buf.  In that case, input_buf_len
+	 * tracks the number of bytes that have been verified as valid in the
+	 * database encoding, and raw_buf_len is the total number of bytes stored
+	 * in the buffer.
+	 */
+#define INPUT_BUF_SIZE 65536	/* we palloc INPUT_BUF_SIZE+1 bytes */
+	char	   *input_buf;
+	int			input_buf_index;	/* next byte to process */
+	int			input_buf_len;	/* total # of bytes stored */
+	bool		input_reached_eof;	/* true if we reached EOF */
+	bool		input_reached_error;	/* true if a conversion error happened */
+	/* Shorthand for number of unconsumed bytes available in input_buf */
+#define INPUT_BUF_BYTES(cstate) ((cstate)->input_buf_len - (cstate)->input_buf_index)
+
+	/*
+	 * raw_buf holds raw input data read from the data source (file or client
+	 * connection), not yet converted to the database encoding.  Like with
+	 * 'input_buf', we guarantee that there is a \0 at raw_buf[raw_buf_len].
+	 */
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+	char	   *raw_buf;
+	int			raw_buf_index;	/* next byte to process */
+	int			raw_buf_len;	/* total # of bytes stored */
+	bool		raw_reached_eof;	/* true if we reached EOF */
+
+	/* Shorthand for number of unconsumed bytes available in raw_buf */
+#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
+
+	uint64		bytes_processed;	/* number of bytes processed so far */
+} CopyFromStateData;
+
+/*
+ * Represents the different dest cases we need to worry about at
+ * the bottom level
+ */
+typedef enum CopyDest
+{
+	COPY_DEST_FILE,				/* to file (or a piped program) */
+	COPY_DEST_FRONTEND,			/* to frontend */
+	COPY_DEST_CALLBACK,			/* to callback function */
+} CopyDest;
+
+/*
+ * This struct contains all the state variables used throughout a COPY TO
+ * operation.
+ *
+ * Multi-byte encodings: all supported client-side encodings encode multi-byte
+ * characters by having the first byte's high bit set. Subsequent bytes of the
+ * character can have the high bit not set. When scanning data in such an
+ * encoding to look for a match to a single-byte (ie ASCII) character, we must
+ * use the full pg_encoding_mblen() machinery to skip over multibyte
+ * characters, else we might find a false match to a trailing byte. In
+ * supported server encodings, there is no possibility of a false match, and
+ * it's faster to make useless comparisons to trailing bytes than it is to
+ * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
+ * when we have to do it the hard way.
+ */
+typedef struct CopyToStateData
+{
+	/* format-specific routines */
+	const struct CopyToRoutine *routine;
+
+	/* low-level state data */
+	CopyDest	copy_dest;		/* type of copy source/destination */
+	FILE	   *copy_file;		/* used if copy_dest == COPY_DEST_FILE */
+	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO */
+
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	Relation	rel;			/* relation to copy to */
+	QueryDesc  *queryDesc;		/* executable query to copy from */
+	List	   *attnumlist;		/* integer list of attnums to copy */
+	char	   *filename;		/* filename, or NULL for STDOUT */
+	bool		is_program;		/* is 'filename' a program to popen? */
+	bool		json_row_delim_needed;	/* need delimiter before next row */
+	StringInfo	json_buf;		/* reusable buffer for JSON output,
+								 * initialized in BeginCopyTo */
+	TupleDesc	tupDesc;		/* Descriptor for JSON output; for a column
+								 * list this is a projected descriptor */
+	Datum	   *json_projvalues;	/* pre-allocated projection values, or
+									 * NULL */
+	bool	   *json_projnulls; /* pre-allocated projection nulls, or NULL */
+	copy_data_dest_cb data_dest_cb; /* function for writing data */
+
+	CopyFormatOptions opts;
+	Node	   *whereClause;	/* WHERE condition (or NULL) */
+	List	   *partitions;		/* OID list of partitions to copy data from */
+
+	/*
+	 * Working state
+	 */
+	MemoryContext copycontext;	/* per-copy execution context */
+
+	FmgrInfo   *out_functions;	/* lookup info for output functions */
+	MemoryContext rowcontext;	/* per-row evaluation context */
+	uint64		bytes_processed;	/* number of bytes processed so far */
+} CopyToStateData;
+
+#endif							/* COPY_STATE_H */
diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h
index 9d3e244ee55..f7afade9a39 100644
--- a/src/include/commands/copyfrom_internal.h
+++ b/src/include/commands/copyfrom_internal.h
@@ -14,31 +14,7 @@
 #ifndef COPYFROM_INTERNAL_H
 #define COPYFROM_INTERNAL_H
 
-#include "commands/copy.h"
-#include "commands/trigger.h"
-#include "nodes/miscnodes.h"
-
-/*
- * Represents the different source cases we need to worry about at
- * the bottom level
- */
-typedef enum CopySource
-{
-	COPY_FILE,					/* from file (or a piped program) */
-	COPY_FRONTEND,				/* from frontend */
-	COPY_CALLBACK,				/* from callback function */
-} CopySource;
-
-/*
- *	Represents the end-of-line terminator type of the input
- */
-typedef enum EolType
-{
-	EOL_UNKNOWN,
-	EOL_NL,
-	EOL_CR,
-	EOL_CRNL,
-} EolType;
+#include "commands/copy_state.h"
 
 /*
  * Represents the insert method to be used during COPY FROM.
@@ -52,145 +28,6 @@ typedef enum CopyInsertMethod
 								 * ExecForeignBatchInsert only if valid */
 } CopyInsertMethod;
 
-/*
- * This struct contains all the state variables used throughout a COPY FROM
- * operation.
- */
-typedef struct CopyFromStateData
-{
-	/* format routine */
-	const struct CopyFromRoutine *routine;
-
-	/* low-level state data */
-	CopySource	copy_src;		/* type of copy source */
-	FILE	   *copy_file;		/* used if copy_src == COPY_FILE */
-	StringInfo	fe_msgbuf;		/* used if copy_src == COPY_FRONTEND */
-
-	EolType		eol_type;		/* EOL type of input */
-	int			file_encoding;	/* file or remote side's character encoding */
-	bool		need_transcoding;	/* file encoding diff from server? */
-	Oid			conversion_proc;	/* encoding conversion function */
-
-	/* parameters from the COPY command */
-	Relation	rel;			/* relation to copy from */
-	List	   *attnumlist;		/* integer list of attnums to copy */
-	char	   *filename;		/* filename, or NULL for STDIN */
-	bool		is_program;		/* is 'filename' a program to popen? */
-	copy_data_source_cb data_source_cb; /* function for reading data */
-
-	CopyFormatOptions opts;
-	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
-	Node	   *whereClause;	/* WHERE condition (or NULL) */
-
-	/* these are just for error messages, see CopyFromErrorCallback */
-	const char *cur_relname;	/* table name for error messages */
-	uint64		cur_lineno;		/* line number for error messages */
-	const char *cur_attname;	/* current att for error messages */
-	const char *cur_attval;		/* current att value for error messages */
-	bool		relname_only;	/* don't output line number, att, etc. */
-
-	/*
-	 * Working state
-	 */
-	MemoryContext copycontext;	/* per-copy execution context */
-
-	AttrNumber	num_defaults;	/* count of att that are missing and have
-								 * default value */
-	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
-	Oid		   *typioparams;	/* array of element types for in_functions */
-	ErrorSaveContext *escontext;	/* soft error trapped during in_functions
-									 * execution */
-	uint64		num_errors;		/* total number of rows which contained soft
-								 * errors */
-	int		   *defmap;			/* array of default att numbers related to
-								 * missing att */
-	ExprState **defexprs;		/* array of default att expressions for all
-								 * att */
-	bool	   *defaults;		/* if DEFAULT marker was found for
-								 * corresponding att */
-	bool		simd_enabled;	/* use SIMD to scan for special chars? */
-
-	/*
-	 * True if the corresponding attribute's is a constrained domain. This
-	 * will be populated only when ON_ERROR is SET_NULL, otherwise NULL.
-	 */
-	bool	   *domain_with_constraint;
-
-	bool		volatile_defexprs;	/* is any of defexprs volatile? */
-	List	   *range_table;	/* single element list of RangeTblEntry */
-	List	   *rteperminfos;	/* single element list of RTEPermissionInfo */
-	ExprState  *qualexpr;
-
-	TransitionCaptureState *transition_capture;
-
-	/*
-	 * These variables are used to reduce overhead in COPY FROM.
-	 *
-	 * attribute_buf holds the separated, de-escaped text for each field of
-	 * the current line.  The CopyReadAttributes functions return arrays of
-	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
-	 * the buffer on each cycle.
-	 *
-	 * In binary COPY FROM, attribute_buf holds the binary data for the
-	 * current field, but the usage is otherwise similar.
-	 */
-	StringInfoData attribute_buf;
-
-	/* field raw data pointers found by COPY FROM */
-
-	int			max_fields;
-	char	  **raw_fields;
-
-	/*
-	 * Similarly, line_buf holds the whole input line being processed. The
-	 * input cycle is first to read the whole line into line_buf, and then
-	 * extract the individual attribute fields into attribute_buf.  line_buf
-	 * is preserved unmodified so that we can display it in error messages if
-	 * appropriate.  (In binary mode, line_buf is not used.)
-	 */
-	StringInfoData line_buf;
-	bool		line_buf_valid; /* contains the row being processed? */
-
-	/*
-	 * input_buf holds input data, already converted to database encoding.
-	 *
-	 * In text mode, CopyReadLine parses this data sufficiently to locate line
-	 * boundaries, then transfers the data to line_buf. We guarantee that
-	 * there is a \0 at input_buf[input_buf_len] at all times.  (In binary
-	 * mode, input_buf is not used.)
-	 *
-	 * If encoding conversion is not required, input_buf is not a separate
-	 * buffer but points directly to raw_buf.  In that case, input_buf_len
-	 * tracks the number of bytes that have been verified as valid in the
-	 * database encoding, and raw_buf_len is the total number of bytes stored
-	 * in the buffer.
-	 */
-#define INPUT_BUF_SIZE 65536	/* we palloc INPUT_BUF_SIZE+1 bytes */
-	char	   *input_buf;
-	int			input_buf_index;	/* next byte to process */
-	int			input_buf_len;	/* total # of bytes stored */
-	bool		input_reached_eof;	/* true if we reached EOF */
-	bool		input_reached_error;	/* true if a conversion error happened */
-	/* Shorthand for number of unconsumed bytes available in input_buf */
-#define INPUT_BUF_BYTES(cstate) ((cstate)->input_buf_len - (cstate)->input_buf_index)
-
-	/*
-	 * raw_buf holds raw input data read from the data source (file or client
-	 * connection), not yet converted to the database encoding.  Like with
-	 * 'input_buf', we guarantee that there is a \0 at raw_buf[raw_buf_len].
-	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
-	char	   *raw_buf;
-	int			raw_buf_index;	/* next byte to process */
-	int			raw_buf_len;	/* total # of bytes stored */
-	bool		raw_reached_eof;	/* true if we reached EOF */
-
-	/* Shorthand for number of unconsumed bytes available in raw_buf */
-#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
-
-	uint64		bytes_processed;	/* number of bytes processed so far */
-} CopyFromStateData;
-
 extern void ReceiveCopyBegin(CopyFromState cstate);
 extern void ReceiveCopyBinaryHeader(CopyFromState cstate);
 
-- 
2.54.0

---

From: Sutou Kouhei <[email-masked]>
Date: Tue, 23 Jun 2026 14:41:49 +0900 (JST)

Hi,

Thanks for restarting this.

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Mon, 22 Jun 2026 18:06:07 -0700,

+1

+1

> +							const CopyFromRoutine **from, ProcessOneOptionFn * option_fn)

How about returning CopyCustomFormatEntry instead? The
function name is "Get...Routines" but it also returns
ProcessOneOptionFn. "Get...Routines" is a bit strange.

> +typedef bool (*ProcessOneOptionFn) (CopyFormatOptions *opts, bool is_from,

How about adding "Copy" keyword to the type name such as
"ProcessOneCopyOptionFn" because this is only for COPY format?

> +#define CopyFormatBuiltins(format) ((format) != COPY_FORMAT_CUSTOM)

How about renaming this to CopyFormatIsBuiltin() or
something? "...Builtins" is a bit strange because this
returns a boolean.

> +typedef void (*ValidateOptionsFn) (CopyFormatOptions *opts, bool is_from);

How about adding "Copy" keyword like "ValidateCopyOptionsFn"?

This is not a blocker but we may want to add
InitializeCopyOptions callback for this.

Thanks,
-- 
kou

---

From: Masahiko Sawada <[email-masked]>
Date: Tue, 23 Jun 2026 18:15:10 -0700

Agreed.

Agreed.

Agreed.

Agreed.

> InitializeCopyOptions callback for this.

It would save just a few lines. It might be worth having the
initialization callback if it would enable extensions to do what
cannot be done with the current proposed callbacks.

Thank you for reviewing the patches! I've attached updated patches.
I'll verify that the new API works well with an experimental custom
copy format extension.

Regards,

-- 
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com
From 43c06a26a14c914f6bc3d72d01accd95e3b0f8e8 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <[email-masked]>
Date: Mon, 22 Jun 2026 09:23:09 -0700
Subject: [PATCH v3 3/4] Add an hook for custom COPY format option validation.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
---
 src/backend/commands/copy.c    |  9 +++++++++
 src/backend/commands/copyapi.c |  4 +++-
 src/include/commands/copyapi.h | 14 +++++++++++++-
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 0fda54905cd..dab523c68db 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -1119,6 +1119,15 @@ ProcessCopyOptions(ParseState *pstate,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 					 errmsg("COPY format \"%s\" cannot be used with COPY TO",
 							opts_out->custom_format_ent->name)));
+
+		/*
+		 * Let the format validate its fully-parsed options as a whole.  This
+		 * runs even when no format-specific options were given, so a format
+		 * can reject incompatible core options or enforce cross-option
+		 * constraints.
+		 */
+		if (opts_out->custom_format_ent->validate_fn != NULL)
+			opts_out->custom_format_ent->validate_fn(opts_out, is_from);
 	}
 }
 
diff --git a/src/backend/commands/copyapi.c b/src/backend/commands/copyapi.c
index f007d73e867..29fb98ff4c2 100644
--- a/src/backend/commands/copyapi.c
+++ b/src/backend/commands/copyapi.c
@@ -48,7 +48,8 @@ is_builtin_copy_format(const char *name)
  */
 void
 RegisterCopyCustomFormat(const char *name, const CopyToRoutine *to,
-						 const CopyFromRoutine *from, ProcessOneCopyOptionFn option_fn)
+						 const CopyFromRoutine *from, ProcessOneCopyOptionFn option_fn,
+						 ValidateCopyOptionsFn validate_fn)
 {
 	Assert(name != NULL && name[0] != '\0');
 
@@ -94,6 +95,7 @@ RegisterCopyCustomFormat(const char *name, const CopyToRoutine *to,
 
diff --git a/src/include/commands/copyapi.h b/src/include/commands/copyapi.h
index 1b323b23bba..f1924424df8 100644
--- a/src/include/commands/copyapi.h
+++ b/src/include/commands/copyapi.h
@@ -117,6 +117,15 @@ typedef struct CopyFromRoutine
 typedef bool (*ProcessOneCopyOptionFn) (CopyFormatOptions *opts, bool is_from,
 										DefElem *option);
 
+/*
+ * Optional callback to validate a custom format's fully-parsed options as a
+ * whole. Invoked once from ProcessCopyOptions() after all options have been
+ * processed, so it can enforce cross-option constraints and reject
+ * incompatible core options. It runs even when no format-specific options were
+ * supplied. Reports problems with ereport().
+ */
+typedef void (*ValidateCopyOptionsFn) (CopyFormatOptions *opts, bool is_from);
+
 /*
  * Sturct to store the registered custom format information.
  */
@@ -126,11 +135,14 @@ typedef struct CopyCustomFormatEntry
 	const CopyToRoutine *to_routine;
 	const CopyFromRoutine *from_routine;
 	ProcessOneCopyOptionFn option_fn;
+	ValidateCopyOptionsFn validate_fn;
 } CopyCustomFormatEntry;
 
 extern void RegisterCopyCustomFormat(const char *name, const CopyToRoutine *to,
 									 const CopyFromRoutine *from,
-									 ProcessOneCopyOptionFn option_fn);
+									 ProcessOneCopyOptionFn option_fn,
+									 ValidateCopyOptionsFn validate_fn);
+
 extern const CopyCustomFormatEntry *GetCopyCustomFormatRoutines(const char *name);
 
 #endif							/* COPYAPI_H */
-- 
2.54.0

From 4b1bbfb28daaa8a177b3a802572ae930fc15d199 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <[email-masked]>
Date: Mon, 22 Jun 2026 09:21:51 -0700
Subject: [PATCH v3 2/4] Allow extensions to register custom format to COPY TO
 and COPY FROM.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
---
 src/backend/commands/Makefile     |   1 +
 src/backend/commands/copy.c       |  90 ++++++++++++++++++++---
 src/backend/commands/copyapi.c    | 114 ++++++++++++++++++++++++++++++
 src/backend/commands/copyfrom.c   |   4 +-
 src/backend/commands/copyto.c     |   4 +-
 src/backend/commands/meson.build  |   1 +
 src/include/commands/copy.h       |  18 +++++
 src/include/commands/copy_state.h |   6 ++
 src/include/commands/copyapi.h    |  31 ++++++++
 src/tools/pgindent/typedefs.list  |   1 +
 10 files changed, 259 insertions(+), 11 deletions(-)
 create mode 100644 src/backend/commands/copyapi.c

index 003b70852bb..0fda54905cd 100644
@@ -592,6 +593,12 @@ ProcessCopyOptions(ParseState *pstate,
 
+	/*
@@ -620,6 +627,8 @@ ProcessCopyOptions(ParseState *pstate,
+			else if ((opts_out->custom_format_ent = GetCopyCustomFormatRoutines(fmt)) != NULL)
@@ -775,11 +784,54 @@ ProcessCopyOptions(ParseState *pstate,
+		if (opts_out->format != COPY_FORMAT_CUSTOM || opts_out->custom_format_ent->option_fn == NULL)
+			if (!opts_out->custom_format_ent->option_fn(opts_out, is_from, opt))
+								opts_out->custom_format_ent->name, opt->defname),
 
 	/*
@@ -869,7 +921,7 @@ ProcessCopyOptions(ParseState *pstate,
 	 * future-proofing.  Likewise we disallow all digits though only octal
 	 * digits are actually dangerous.
 	 */
-	if (opts_out->format != COPY_FORMAT_CSV &&
+	if (CopyFormatIsBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_CSV &&
 		strchr("\\.abcdefghijklmnopqrstuvwxyz0123456789",
 			   opts_out->delim[0]) != NULL)
 		ereport(ERROR,
@@ -888,7 +940,8 @@ ProcessCopyOptions(ParseState *pstate,
 				: errmsg("cannot specify %s in JSON mode", "HEADER"));
 
 	/* Check quote */
-	if (opts_out->format != COPY_FORMAT_CSV && opts_out->quote != NULL)
+	if (CopyFormatIsBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_CSV &&
+		opts_out->quote != NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -905,7 +958,8 @@ ProcessCopyOptions(ParseState *pstate,
 				 errmsg("COPY delimiter and quote must be different")));
 
 	/* Check escape */
-	if (opts_out->format != COPY_FORMAT_CSV && opts_out->escape != NULL)
+	if (CopyFormatIsBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_CSV &&
+		opts_out->escape != NULL)
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -917,7 +971,8 @@ ProcessCopyOptions(ParseState *pstate,
 				 errmsg("COPY escape must be a single one-byte character")));
 
 	/* Check force_quote */
-	if (opts_out->format != COPY_FORMAT_CSV && (opts_out->force_quote || opts_out->force_quote_all))
+	if (CopyFormatIsBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_CSV &&
+		(opts_out->force_quote || opts_out->force_quote_all))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -931,8 +986,8 @@ ProcessCopyOptions(ParseState *pstate,
 						"COPY FROM")));
 
 	/* Check force_notnull */
-	if (opts_out->format != COPY_FORMAT_CSV && (opts_out->force_notnull != NIL ||
-												opts_out->force_notnull_all))
+	if (CopyFormatIsBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_CSV &&
+		(opts_out->force_notnull != NIL || opts_out->force_notnull_all))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -947,8 +1002,8 @@ ProcessCopyOptions(ParseState *pstate,
 						"COPY TO")));
 
 	/* Check force_null */
-	if (opts_out->format != COPY_FORMAT_CSV && (opts_out->force_null != NIL ||
-												opts_out->force_null_all))
+	if (CopyFormatIsBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_CSV &&
+		(opts_out->force_null != NIL || opts_out->force_null_all))
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 		/*- translator: %s is the name of a COPY option, e.g. ON_ERROR */
@@ -995,7 +1050,8 @@ ProcessCopyOptions(ParseState *pstate,
 				errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				errmsg("COPY %s is not supported for %s", "FORMAT JSON", "COPY FROM"));
 
-	if (opts_out->format != COPY_FORMAT_JSON && opts_out->force_array)
+	if (CopyFormatIsBuiltins(opts_out->format) && opts_out->format != COPY_FORMAT_JSON &&
+		opts_out->force_array)
 		ereport(ERROR,
 				errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				errmsg("COPY %s can only be used with JSON mode", "FORCE_ARRAY"));
@@ -1048,6 +1104,22 @@ ProcessCopyOptions(ParseState *pstate,
 		 * ON_ERROR, third is the value of the COPY option, e.g. IGNORE */
 				 errmsg("COPY %s requires %s to be set to %s",
 						"REJECT_LIMIT", "ON_ERROR", "IGNORE")));
+
+	/* Check custom format routines */
+	if (opts_out->format == COPY_FORMAT_CUSTOM)
+	{
+		if (is_from && opts_out->custom_format_ent->from_routine == NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("COPY format \"%s\" cannot be used with COPY FROM",
+							opts_out->custom_format_ent->name)));
+
+		if (!is_from && opts_out->custom_format_ent->to_routine == NULL)
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("COPY format \"%s\" cannot be used with COPY TO",
+							opts_out->custom_format_ent->name)));
+	}
 }
 
 /*
index 00000000000..f007d73e867
@@ -0,0 +1,114 @@
+						 const CopyFromRoutine *from, ProcessOneCopyOptionFn option_fn)
+ * Look up a previously registered custom format. Returns NULL if 'name' is
+ * not registered.
+const CopyCustomFormatEntry *
+GetCopyCustomFormatRoutines(const char *name)
+			return &(CopyCustomFormatArray[i]);
+	return NULL;
index 2c57b32f4de..ff4fa718e56 100644
+		return opts->custom_format_ent->from_routine;
index ef2038c9a5d..72cc1ac8d8d 100644
+		return opts->custom_format_ent->to_routine;
index 5e710efff5b..77c652818cb 100644
+#define CopyFormatIsBuiltins(format) ((format) != COPY_FORMAT_CUSTOM)
 
 /*
@@ -97,6 +106,15 @@ typedef struct CopyFormatOptions
+	const struct CopyCustomFormatEntry *custom_format_ent;

 
 /*
 
index 398e7a78bb3..1b323b23bba 100644

 /*
@@ -102,4 +103,34 @@ typedef struct CopyFromRoutine
 	void		(*CopyFromEnd) (CopyFromState cstate);
 } CopyFromRoutine;
 
+/*
+typedef bool (*ProcessOneCopyOptionFn) (CopyFormatOptions *opts, bool is_from,
+ * Sturct to store the registered custom format information.
+	ProcessOneCopyOptionFn option_fn;
+									 ProcessOneCopyOptionFn option_fn);
+extern const CopyCustomFormatEntry *GetCopyCustomFormatRoutines(const char *name);

From b5ff7ebea3141625b8699c85a3bf15972b1e1537 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <[email-masked]>
Date: Mon, 22 Jun 2026 13:14:31 -0700
Subject: [PATCH v3 4/4] Add test module for COPY custom format.

Author:
Reviewed-by:

From 47aa927d65e483331f9b2010499b4c7f0bfb562c Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <[email-masked]>
Date: Mon, 22 Jun 2026 11:50:27 -0700
Subject: [PATCH v3 1/4] Move Copy[From|To]StateData to copy_state.h.

Author:
Reviewed-by:

 

 
 
-/*
 
 	pq_endmessage(&buf);
 
 static void

 
 	if (data_dest_cb)
 	{

 
 
 /*
 
-/*
 
-- 
2.54.0

---

From: Sutou Kouhei <[email-masked]>
Date: Fri, 26 Jun 2026 12:21:50 +0900 (JST)

Hi,

In <[email-masked]>
  "Re: Make COPY format extendable: Extract COPY TO format implementations" on Tue, 23 Jun 2026 18:15:10 -0700,

+1

I have only a few minor comments:

> +						 const CopyFromRoutine *from, ProcessOneCopyOptionFn option_fn)

How about using "const CopyCustomFormatEntry *" instead of
"to", "from" and "option_fn"? If we use
CopyCustomFormatEntry here, we don't need change the
signature of this function when we add more items.

> +GetCopyCustomFormatRoutines(const char *name)

How about renaming this to "...FormatEntry" from
"...FormatRoutines"?

> +#define CopyFormatIsBuiltins(format) ((format) != COPY_FORMAT_CUSTOM)

How about removing the last "s" ("...IsBuiltin") because
this processes only one format?

> +	const struct CopyCustomFormatEntry *custom_format_ent;

It may be better that we don't abbreviate "_entry" to "_ent"
here for readability. It seems that we use this abbreviation
only in a few places:

$ git grep '_ent;' src/
src/backend/replication/logical/reorderbuffer.c:		ReorderBufferTupleCidEnt *new_ent;
src/backend/utils/cache/catcache.c:	CatCInProgress in_progress_ent;
src/backend/utils/cache/catcache.c:	catcache_in_progress_stack = &in_progress_ent;
src/backend/utils/cache/catcache.c:			CatCInProgress in_progress_ent;
src/backend/utils/cache/catcache.c:			catcache_in_progress_stack = &in_progress_ent;

> I'll verify that the new API works well with an experimental custom

I think that we need to provide more APIs to read/write data
like we did in v40-0003 to implement a custom copy format
extension:
https://www.postgresql.org/message-id/flat/20250425.214534.1841428689427124725.kou%40clear-code.com

At least https://github.com/kou/pg-copy-arrow needs them.

Thanks,
-- 
kou