Skip to content

Commit 12ab58d

Browse files
elpransElvis Pranskevichus
authored and
Elvis Pranskevichus
committed
Add infrastructure for multiformat data codecs
Current asyncpg codec architecture allows for only one codec per data type. This arrangement works most of the time, but fails utterly to handle situations when the text format I/O is forced by the lack of binary I/O support for one of the types in the composite type. This commit is the preparation for the introduction of text format parsing and allows to associate multiple format-specific codecs for each type.
1 parent 678f683 commit 12ab58d

File tree

6 files changed

+149
-74
lines changed

6 files changed

+149
-74
lines changed

asyncpg/introspection.py

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
INTRO_LOOKUP_TYPES = '''\
99
WITH RECURSIVE typeinfo_tree(
10-
oid, ns, name, kind, basetype, elemtype, range_subtype,
11-
elem_has_bin_input, elem_has_bin_output, attrtypoids, attrnames, depth)
10+
oid, ns, name, kind, basetype, has_bin_io, elemtype, elemdelim,
11+
range_subtype, elem_has_bin_io, attrtypoids, attrnames, depth)
1212
AS (
1313
WITH composite_attrs
1414
AS (
@@ -58,10 +58,23 @@
5858
5959
ELSE NULL
6060
END) AS basetype,
61+
t.typreceive::oid != 0 AND t.typsend::oid != 0
62+
AS has_bin_io,
6163
t.typelem AS elemtype,
64+
elem_t.typdelim AS elemdelim,
6265
range_t.rngsubtype AS range_subtype,
63-
elem_t.typreceive::oid != 0 AS elem_has_bin_input,
64-
elem_t.typsend::oid != 0 AS elem_has_bin_output,
66+
(CASE WHEN t.typtype = 'r' THEN
67+
(SELECT
68+
range_elem_t.typreceive::oid != 0 AND
69+
range_elem_t.typsend::oid != 0
70+
FROM
71+
pg_catalog.pg_type AS range_elem_t
72+
WHERE
73+
range_elem_t.oid = range_t.rngsubtype)
74+
ELSE
75+
elem_t.typreceive::oid != 0 AND
76+
elem_t.typsend::oid != 0
77+
END) AS elem_has_bin_io,
6578
(CASE WHEN t.typtype = 'c' THEN
6679
(SELECT ca.typoids
6780
FROM composite_attrs AS ca
@@ -91,8 +104,8 @@
91104
)
92105
93106
SELECT
94-
ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.elemtype,
95-
ti.range_subtype, ti.elem_has_bin_input, ti.elem_has_bin_output,
107+
ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.has_bin_io,
108+
ti.elemtype, ti.elemdelim, ti.range_subtype, ti.elem_has_bin_io,
96109
ti.attrtypoids, ti.attrnames, 0
97110
FROM
98111
typeinfo AS ti
@@ -102,8 +115,8 @@
102115
UNION ALL
103116
104117
SELECT
105-
ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.elemtype,
106-
ti.range_subtype, ti.elem_has_bin_input, ti.elem_has_bin_output,
118+
ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.has_bin_io,
119+
ti.elemtype, ti.elemdelim, ti.range_subtype, ti.elem_has_bin_io,
107120
ti.attrtypoids, ti.attrnames, tt.depth + 1
108121
FROM
109122
typeinfo ti,
@@ -126,8 +139,8 @@
126139
# Prior to 9.2 PostgreSQL did not have range types.
127140
INTRO_LOOKUP_TYPES_91 = '''\
128141
WITH RECURSIVE typeinfo_tree(
129-
oid, ns, name, kind, basetype, elemtype, range_subtype,
130-
elem_has_bin_input, elem_has_bin_output, attrtypoids, attrnames, depth)
142+
oid, ns, name, kind, basetype, has_bin_io, elemtype, elemdelim,
143+
range_subtype, elem_has_bin_io, attrtypoids, attrnames, depth)
131144
AS (
132145
WITH composite_attrs
133146
AS (
@@ -177,10 +190,14 @@
177190
178191
ELSE NULL
179192
END) AS basetype,
193+
t.typreceive::oid != 0 AND t.typsend::oid != 0
194+
AS has_bin_io,
180195
t.typelem AS elemtype,
196+
elem_t.typdelim AS elemdelim,
181197
NULL::oid AS range_subtype,
182-
elem_t.typreceive::oid != 0 AS elem_has_bin_input,
183-
elem_t.typsend::oid != 0 AS elem_has_bin_output,
198+
elem_t.typreceive::oid != 0 AND
199+
elem_t.typsend::oid != 0
200+
AS elem_has_bin_io,
184201
(CASE WHEN t.typtype = 'c' THEN
185202
(SELECT ca.typoids
186203
FROM composite_attrs AS ca
@@ -207,8 +224,8 @@
207224
)
208225
209226
SELECT
210-
ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.elemtype,
211-
ti.range_subtype, ti.elem_has_bin_input, ti.elem_has_bin_output,
227+
ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.has_bin_io,
228+
ti.elemtype, ti.elemdelim, ti.range_subtype, ti.elem_has_bin_io,
212229
ti.attrtypoids, ti.attrnames, 0
213230
FROM
214231
typeinfo AS ti
@@ -218,8 +235,8 @@
218235
UNION ALL
219236
220237
SELECT
221-
ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.elemtype,
222-
ti.range_subtype, ti.elem_has_bin_input, ti.elem_has_bin_output,
238+
ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, ti.has_bin_io,
239+
ti.elemtype, ti.elemdelim, ti.range_subtype, ti.elem_has_bin_io,
223240
ti.attrtypoids, ti.attrnames, tt.depth + 1
224241
FROM
225242
typeinfo ti,

asyncpg/protocol/codecs/base.pxd

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ cdef enum CodecType:
3232

3333

3434
cdef enum CodecFormat:
35+
PG_FORMAT_ANY = -1
3536
PG_FORMAT_TEXT = 0
3637
PG_FORMAT_BINARY = 1
3738

@@ -55,6 +56,7 @@ cdef class Codec:
5556

5657
# arrays
5758
Codec element_codec
59+
Py_UCS4 element_delimiter
5860

5961
# composite types
6062
tuple element_type_oids
@@ -70,7 +72,8 @@ cdef class Codec:
7072
encode_func c_encoder, decode_func c_decoder,
7173
object py_encoder, object py_decoder,
7274
Codec element_codec, tuple element_type_oids,
73-
object element_names, list element_codecs)
75+
object element_names, list element_codecs,
76+
Py_UCS4 element_delimiter)
7477

7578
cdef encode_scalar(self, ConnectionSettings settings, WriteBuffer buf,
7679
object obj)
@@ -118,7 +121,8 @@ cdef class Codec:
118121
cdef Codec new_array_codec(uint32_t oid,
119122
str name,
120123
str schema,
121-
Codec element_codec)
124+
Codec element_codec,
125+
Py_UCS4 element_delimiter)
122126

123127
@staticmethod
124128
cdef Codec new_range_codec(uint32_t oid,
@@ -149,4 +153,4 @@ cdef class DataCodecConfig:
149153
dict _type_codecs_cache
150154
dict _local_type_codecs
151155

152-
cdef inline Codec get_codec(self, uint32_t oid)
156+
cdef inline Codec get_codec(self, uint32_t oid, CodecFormat format)

0 commit comments

Comments
 (0)