CopyIn
struct CopyInA COPY ... FROM STDIN in progress: write rows, then finish.
Created by connection.Connection.copy_in. Bytes written here are the
COPY data itself in the format the statement declared -- text by default,
CSV with (FORMAT csv) -- which copyfmt.CopyEncoder produces.
Chunks need not align with rows on the way to CopyIn.write, but
CopyIn.finish must not be called mid-row: flush whole rows.
CopyIn.write_rows does that for you.
Finish it, or it is aborted. CopyIn.finish is what commits the
rows; if the handle is destroyed first -- an early return, a raised error
-- CopyIn.abort runs instead and the server discards everything the
stream carried. Nothing is half-loaded either way, since COPY is a
single statement and rolls back as one.
Like connection.Statement, this shares ownership of the connection
rather than borrowing it, so the session stays open for as long as the
COPY does even if the Connection value was dropped first -- which Mojo
does at its last use. An explicit connection.Connection.close ends the
COPY: every call then raises SQLSTATE 08006.
Implements Movable
__init__
def __init__(out self, cell: ArcPointer[_ConnCell], sql: String) Record a COPY that libpq has already put into PGRES_COPY_IN.
connection.Connection.copy_in is the only intended caller: it runs
the statement and checks the status before constructing this.
- Args
cell: The shared cell of the connection the COPY is running on; a share of it is kept, so the connection stays open at least as long as this handle does.sql: TheCOPYstatement text.
__deinit__
def __deinit__(deinit self) Abort the COPY unless it was already finished or aborted.
The server is told the stream failed and discards it, and the outstanding results are drained so the connection is idle again. Errors are swallowed -- a destructor has nobody to raise to -- and a connection that has been closed is left alone.
is_open
def is_open(self) -> Bool Whether the COPY is still accepting data.
write
def write(mut self, data: Span[UInt8]) Queue data as the next bytes of the COPY stream.
libpq copies the bytes into its own buffer before returning, so nothing has to be kept alive afterwards.
- Args
data: Raw COPY data, in the format the statement declared. Not required to end on a row boundary; an empty span is a no-op.
Raises Error: A sqlstate.PostgresError if the COPY is already finished,
or if libpq could not queue the data -- which means the
connection has gone. A row the server rejects is not
reported here; see CopyIn.finish.
def write(mut self, data: String) Queue data as the next bytes of the COPY stream.
The overload for callers holding text rather than bytes -- both COPY sub-formats this tin encodes are text.
- Args
data: Raw COPY data, in the format the statement declared.
Raises Error: A sqlstate.PostgresError if the COPY is already finished
or the data could not be queued.
write_rows
def write_rows(mut self, mut encoder: CopyEncoder) Flush everything buffered in encoder into the stream.
The usual way to drive a COPY: append rows to the encoder, and call
this whenever copyfmt.CopyEncoder.size has grown enough to be worth
a write. The encoder is emptied, so the same one can be refilled and
flushed again as many times as the load needs.
- Args
encoder: The encoder to take the buffered bytes from. Flush only aftercopyfmt.CopyEncoder.end_row: a partial row would split across writes correctly, butCopyIn.finishmust not land in the middle of one.
Raises Error: A sqlstate.PostgresError if the COPY is already finished
or the data could not be queued.
finish
def finish(mut self) -> Int End the stream, commit the rows, and report how many there were.
Every write so far is flushed, the server finishes reading, and the outstanding results are drained -- which is where the server's verdict on the data arrives.
Raises Error: A sqlstate.PostgresError if the COPY was already
finished, or if the server rejected the data. A malformed row
is the usual cause and reports the type's own SQLSTATE --
22P02 for text that is not a valid number -- with the
offending line in the error's CONTEXT. The connection is
idle and usable afterwards either way.
abort
def abort(mut self, reason: String = "COPY aborted by the client") End the stream by failing it, so the server discards every row.
The deliberate counterpart to CopyIn.finish, and what the destructor
does on its own. This does not raise: the failure is the point.
- Args
reason: The text the server attaches to the error it records for the aborted COPY. It appears in the server log, not in anything raised here.
Raises Error: Only if the COPY was already finished or aborted. The abort itself is silent, whatever libpq makes of it.