Skip to content

Commit c9d3343

Browse files
Dev-iLclaude
andcommitted
Move COPY FROM STDIN docs to a dedicated page
Consolidates binary_copy_to_table and copy_records_to_table docs into docs/components/copy.md with tabbed Connection/Transaction examples. connection.md and transaction.md now reference that page instead of duplicating the content. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent feea29c commit c9d3343

4 files changed

Lines changed: 151 additions & 147 deletions

File tree

docs/.vuepress/sidebar.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export default sidebar({
2222
"connection_pool_builder",
2323
"connection",
2424
"transaction",
25+
"copy",
2526
"cursor",
2627
"prepared_statement",
2728
"listener",

docs/components/connection.md

Lines changed: 3 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -245,80 +245,10 @@ async def main() -> None:
245245
)
246246
```
247247

248-
### Binary Copy To Table
248+
### COPY FROM STDIN
249249

250-
#### Parameters:
251-
252-
- `source`: bytes, bytearray, or `BytesIO` containing a PostgreSQL binary COPY stream.
253-
- `table_name`: name of the target table.
254-
- `columns`: sequence of column names to load into. When `None`, all table columns are used in their declared order.
255-
- `schema_name`: optional schema for `table_name`.
256-
257-
Stream a pre-encoded PostgreSQL binary COPY payload directly into a table.
258-
Executes `COPY table_name (<columns>) FROM STDIN (FORMAT binary)`.
259-
260-
::: warning
261-
You are responsible for encoding the bytes correctly. Passing an invalid binary COPY stream will result in a database error.
262-
:::
263-
264-
```python
265-
async def main() -> None:
266-
...
267-
connection = await db_pool.connection()
268-
with open("data.bin", "rb") as f:
269-
inserted = await connection.binary_copy_to_table(
270-
source=f.read(),
271-
table_name="users",
272-
columns=["id", "username"],
273-
)
274-
print(f"Inserted {inserted} rows")
275-
```
276-
277-
### Copy Records To Table
278-
279-
#### Parameters:
280-
281-
- `table_name`: name of the target table.
282-
- `records`: iterable of records, where each record is a sequence of column values.
283-
- `columns`: sequence of column names to load into. When `None`, all table columns are used in their declared order.
284-
- `schema_name`: optional schema for `table_name`.
285-
286-
Bulk-load plain Python records into a table via the binary `COPY FROM STDIN` protocol.
287-
Column types are introspected from the target table automatically, so each record may contain ordinary Python values — the same types accepted by `execute()`.
288-
Returns the number of inserted rows.
289-
290-
This is the ergonomic alternative to `binary_copy_to_table` when you have Python data rather than a pre-encoded binary stream.
291-
292-
```python
293-
from datetime import datetime, timezone
294-
295-
async def main() -> None:
296-
...
297-
connection = await db_pool.connection()
298-
records = [
299-
(1, "alpha", 1.5, datetime(2026, 1, 1, tzinfo=timezone.utc)),
300-
(2, "beta", 2.25, datetime(2026, 1, 2, tzinfo=timezone.utc)),
301-
(3, "gamma", None, datetime(2026, 1, 3, tzinfo=timezone.utc)),
302-
]
303-
inserted = await connection.copy_records_to_table(
304-
table_name="measurements",
305-
records=records,
306-
)
307-
print(f"Inserted {inserted} rows")
308-
```
309-
310-
You can load only a subset of columns by providing the `columns` argument:
311-
312-
```python
313-
async def main() -> None:
314-
...
315-
connection = await db_pool.connection()
316-
inserted = await connection.copy_records_to_table(
317-
table_name="measurements",
318-
records=[(1, "alpha"), (2, "beta")],
319-
columns=["id", "label"],
320-
)
321-
```
250+
`Connection` supports bulk-loading via `binary_copy_to_table` and `copy_records_to_table`.
251+
See the [COPY FROM STDIN](./copy.md) page for full documentation and examples.
322252

323253
### Close
324254
Returns connection to the pool.

docs/components/copy.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
---
2+
title: COPY FROM STDIN
3+
---
4+
5+
PSQLPy exposes two methods for bulk-loading data via PostgreSQL's `COPY FROM STDIN` protocol.
6+
Both are available on `Connection` and `Transaction`.
7+
8+
## Binary Copy To Table
9+
10+
#### Parameters:
11+
12+
- `source`: bytes, bytearray, or `BytesIO` containing a PostgreSQL binary COPY stream.
13+
- `table_name`: name of the target table.
14+
- `columns`: sequence of column names to load into. When `None`, all table columns are used in their declared order.
15+
- `schema_name`: optional schema for `table_name`.
16+
17+
Stream a pre-encoded PostgreSQL binary COPY payload directly into a table.
18+
Executes `COPY table_name (<columns>) FROM STDIN (FORMAT binary)`.
19+
20+
::: warning
21+
You are responsible for encoding the bytes correctly. Passing an invalid binary COPY stream will result in a database error.
22+
:::
23+
24+
::: tabs
25+
26+
@tab Connection
27+
```python
28+
async def main() -> None:
29+
...
30+
connection = await db_pool.connection()
31+
with open("data.bin", "rb") as f:
32+
inserted = await connection.binary_copy_to_table(
33+
source=f.read(),
34+
table_name="users",
35+
columns=["id", "username"],
36+
)
37+
print(f"Inserted {inserted} rows")
38+
```
39+
40+
@tab Transaction
41+
```python
42+
async def main() -> None:
43+
...
44+
connection = await db_pool.connection()
45+
async with connection.transaction() as transaction:
46+
with open("data.bin", "rb") as f:
47+
inserted = await transaction.binary_copy_to_table(
48+
source=f.read(),
49+
table_name="users",
50+
columns=["id", "username"],
51+
)
52+
print(f"Inserted {inserted} rows")
53+
```
54+
55+
:::
56+
57+
## Copy Records To Table
58+
59+
#### Parameters:
60+
61+
- `table_name`: name of the target table.
62+
- `records`: iterable of records, where each record is a sequence of column values.
63+
- `columns`: sequence of column names to load into. When `None`, all table columns are used in their declared order.
64+
- `schema_name`: optional schema for `table_name`.
65+
66+
Bulk-load plain Python records into a table via the binary `COPY FROM STDIN` protocol.
67+
Column types are introspected from the target table automatically, so each record may contain ordinary Python values — the same types accepted by `execute()`.
68+
Returns the number of inserted rows.
69+
70+
This is the ergonomic alternative to `binary_copy_to_table` when you have Python data rather than a pre-encoded binary stream.
71+
72+
::: tabs
73+
74+
@tab Connection
75+
```python
76+
from datetime import datetime, timezone
77+
78+
async def main() -> None:
79+
...
80+
connection = await db_pool.connection()
81+
records = [
82+
(1, "alpha", 1.5, datetime(2026, 1, 1, tzinfo=timezone.utc)),
83+
(2, "beta", 2.25, datetime(2026, 1, 2, tzinfo=timezone.utc)),
84+
(3, "gamma", None, datetime(2026, 1, 3, tzinfo=timezone.utc)),
85+
]
86+
inserted = await connection.copy_records_to_table(
87+
table_name="measurements",
88+
records=records,
89+
)
90+
print(f"Inserted {inserted} rows")
91+
```
92+
93+
@tab Transaction
94+
```python
95+
from datetime import datetime, timezone
96+
97+
async def main() -> None:
98+
...
99+
connection = await db_pool.connection()
100+
records = [
101+
(1, "alpha", 1.5, datetime(2026, 1, 1, tzinfo=timezone.utc)),
102+
(2, "beta", 2.25, datetime(2026, 1, 2, tzinfo=timezone.utc)),
103+
(3, "gamma", None, datetime(2026, 1, 3, tzinfo=timezone.utc)),
104+
]
105+
async with connection.transaction() as transaction:
106+
inserted = await transaction.copy_records_to_table(
107+
table_name="measurements",
108+
records=records,
109+
)
110+
print(f"Inserted {inserted} rows")
111+
```
112+
113+
:::
114+
115+
You can load only a subset of columns by providing the `columns` argument:
116+
117+
::: tabs
118+
119+
@tab Connection
120+
```python
121+
async def main() -> None:
122+
...
123+
connection = await db_pool.connection()
124+
inserted = await connection.copy_records_to_table(
125+
table_name="measurements",
126+
records=[(1, "alpha"), (2, "beta")],
127+
columns=["id", "label"],
128+
)
129+
```
130+
131+
@tab Transaction
132+
```python
133+
async def main() -> None:
134+
...
135+
connection = await db_pool.connection()
136+
async with connection.transaction() as transaction:
137+
inserted = await transaction.copy_records_to_table(
138+
table_name="measurements",
139+
records=[(1, "alpha"), (2, "beta")],
140+
columns=["id", "label"],
141+
)
142+
```
143+
144+
:::

docs/components/transaction.md

Lines changed: 3 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -427,78 +427,7 @@ async def main() -> None:
427427
... # do something with the result.
428428
```
429429

430-
### Binary Copy To Table
430+
### COPY FROM STDIN
431431

432-
#### Parameters:
433-
434-
- `source`: bytes, bytearray, or `BytesIO` containing a PostgreSQL binary COPY stream.
435-
- `table_name`: name of the target table.
436-
- `columns`: sequence of column names to load into. When `None`, all table columns are used in their declared order.
437-
- `schema_name`: optional schema for `table_name`.
438-
439-
Stream a pre-encoded PostgreSQL binary COPY payload directly into a table within the transaction.
440-
Executes `COPY table_name (<columns>) FROM STDIN (FORMAT binary)`.
441-
442-
::: warning
443-
You are responsible for encoding the bytes correctly. Passing an invalid binary COPY stream will result in a database error.
444-
:::
445-
446-
```python
447-
async def main() -> None:
448-
...
449-
connection = await db_pool.connection()
450-
async with connection.transaction() as transaction:
451-
with open("data.bin", "rb") as f:
452-
inserted = await transaction.binary_copy_to_table(
453-
source=f.read(),
454-
table_name="users",
455-
columns=["id", "username"],
456-
)
457-
print(f"Inserted {inserted} rows")
458-
```
459-
460-
### Copy Records To Table
461-
462-
#### Parameters:
463-
464-
- `table_name`: name of the target table.
465-
- `records`: iterable of records, where each record is a sequence of column values.
466-
- `columns`: sequence of column names to load into. When `None`, all table columns are used in their declared order.
467-
- `schema_name`: optional schema for `table_name`.
468-
469-
Bulk-load plain Python records into a table via the binary `COPY FROM STDIN` protocol, within the transaction.
470-
Column types are introspected from the target table automatically, so each record may contain ordinary Python values — the same types accepted by `execute()`.
471-
Returns the number of inserted rows.
472-
473-
```python
474-
from datetime import datetime, timezone
475-
476-
async def main() -> None:
477-
...
478-
connection = await db_pool.connection()
479-
records = [
480-
(1, "alpha", 1.5, datetime(2026, 1, 1, tzinfo=timezone.utc)),
481-
(2, "beta", 2.25, datetime(2026, 1, 2, tzinfo=timezone.utc)),
482-
(3, "gamma", None, datetime(2026, 1, 3, tzinfo=timezone.utc)),
483-
]
484-
async with connection.transaction() as transaction:
485-
inserted = await transaction.copy_records_to_table(
486-
table_name="measurements",
487-
records=records,
488-
)
489-
print(f"Inserted {inserted} rows")
490-
```
491-
492-
You can load only a subset of columns by providing the `columns` argument:
493-
494-
```python
495-
async def main() -> None:
496-
...
497-
connection = await db_pool.connection()
498-
async with connection.transaction() as transaction:
499-
inserted = await transaction.copy_records_to_table(
500-
table_name="measurements",
501-
records=[(1, "alpha"), (2, "beta")],
502-
columns=["id", "label"],
503-
)
504-
```
432+
`Transaction` supports bulk-loading via `binary_copy_to_table` and `copy_records_to_table`.
433+
See the [COPY FROM STDIN](./copy.md) page for full documentation and examples.

0 commit comments

Comments
 (0)