@@ -23,14 +23,25 @@ cdef class Codec:
2323 self .oid = oid
2424 self .type = CODEC_UNDEFINED
2525
26- cdef init(self , str name, str schema, str kind,
27- CodecType type , ServerDataFormat format,
28- ClientExchangeFormat xformat,
29- encode_func c_encoder, decode_func c_decoder,
30- object py_encoder, object py_decoder,
31- Codec element_codec, tuple element_type_oids,
32- object element_names, list element_codecs,
33- Py_UCS4 element_delimiter):
26+ cdef init(
27+ self ,
28+ str name,
29+ str schema,
30+ str kind,
31+ CodecType type ,
32+ ServerDataFormat format,
33+ ClientExchangeFormat xformat,
34+ encode_func c_encoder,
35+ decode_func c_decoder,
36+ Codec base_codec,
37+ object py_encoder,
38+ object py_decoder,
39+ Codec element_codec,
40+ tuple element_type_oids,
41+ object element_names,
42+ list element_codecs,
43+ Py_UCS4 element_delimiter,
44+ ):
3445
3546 self .name = name
3647 self .schema = schema
@@ -40,6 +51,7 @@ cdef class Codec:
4051 self .xformat = xformat
4152 self .c_encoder = c_encoder
4253 self .c_decoder = c_decoder
54+ self .base_codec = base_codec
4355 self .py_encoder = py_encoder
4456 self .py_decoder = py_decoder
4557 self .element_codec = element_codec
@@ -48,6 +60,12 @@ cdef class Codec:
4860 self .element_delimiter = element_delimiter
4961 self .element_names = element_names
5062
63+ if base_codec is not None :
64+ if c_encoder != NULL or c_decoder != NULL :
65+ raise exceptions.InternalClientError(
66+ ' base_codec is mutually exclusive with c_encoder/c_decoder'
67+ )
68+
5169 if element_names is not None :
5270 self .record_desc = record.ApgRecordDesc_New(
5371 element_names, tuple (element_names))
@@ -98,7 +116,7 @@ cdef class Codec:
98116 codec = Codec(self .oid)
99117 codec.init(self .name, self .schema, self .kind,
100118 self .type, self .format, self .xformat,
101- self .c_encoder, self .c_decoder,
119+ self .c_encoder, self .c_decoder, self .base_codec,
102120 self .py_encoder, self .py_decoder,
103121 self .element_codec,
104122 self .element_type_oids, self .element_names,
@@ -196,7 +214,10 @@ cdef class Codec:
196214 raise exceptions.InternalClientError(
197215 ' unexpected data format: {}' .format(self .format))
198216 elif self .xformat == PG_XFORMAT_TUPLE:
199- self .c_encoder(settings, buf, data)
217+ if self .base_codec is not None :
218+ self .base_codec.encode(settings, buf, data)
219+ else :
220+ self .c_encoder(settings, buf, data)
200221 else :
201222 raise exceptions.InternalClientError(
202223 ' unexpected exchange format: {}' .format(self .xformat))
@@ -295,7 +316,10 @@ cdef class Codec:
295316 raise exceptions.InternalClientError(
296317 ' unexpected data format: {}' .format(self .format))
297318 elif self .xformat == PG_XFORMAT_TUPLE:
298- data = self .c_decoder(settings, buf)
319+ if self .base_codec is not None :
320+ data = self .base_codec.decode(settings, buf)
321+ else :
322+ data = self .c_decoder(settings, buf)
299323 else :
300324 raise exceptions.InternalClientError(
301325 ' unexpected exchange format: {}' .format(self .xformat))
@@ -367,8 +391,8 @@ cdef class Codec:
367391 cdef Codec codec
368392 codec = Codec(oid)
369393 codec.init(name, schema, ' array' , CODEC_ARRAY, element_codec.format,
370- PG_XFORMAT_OBJECT, NULL , NULL , None , None , element_codec ,
371- None , None , None , element_delimiter)
394+ PG_XFORMAT_OBJECT, NULL , NULL , None , None , None ,
395+ element_codec, None , None , None , element_delimiter)
372396 return codec
373397
374398 @staticmethod
@@ -379,8 +403,8 @@ cdef class Codec:
379403 cdef Codec codec
380404 codec = Codec(oid)
381405 codec.init(name, schema, ' range' , CODEC_RANGE, element_codec.format,
382- PG_XFORMAT_OBJECT, NULL , NULL , None , None , element_codec ,
383- None , None , None , 0 )
406+ PG_XFORMAT_OBJECT, NULL , NULL , None , None , None ,
407+ element_codec, None , None , None , 0 )
384408 return codec
385409
386410 @staticmethod
@@ -391,7 +415,7 @@ cdef class Codec:
391415 cdef Codec codec
392416 codec = Codec(oid)
393417 codec.init(name, schema, ' multirange' , CODEC_MULTIRANGE,
394- element_codec.format, PG_XFORMAT_OBJECT, NULL , NULL ,
418+ element_codec.format, PG_XFORMAT_OBJECT, NULL , NULL , None ,
395419 None , None , element_codec, None , None , None , 0 )
396420 return codec
397421
@@ -407,7 +431,7 @@ cdef class Codec:
407431 codec = Codec(oid)
408432 codec.init(name, schema, ' composite' , CODEC_COMPOSITE,
409433 format, PG_XFORMAT_OBJECT, NULL , NULL , None , None , None ,
410- element_type_oids, element_names, element_codecs, 0 )
434+ None , element_type_oids, element_names, element_codecs, 0 )
411435 return codec
412436
413437 @staticmethod
@@ -419,12 +443,13 @@ cdef class Codec:
419443 object decoder,
420444 encode_func c_encoder,
421445 decode_func c_decoder,
446+ Codec base_codec,
422447 ServerDataFormat format,
423448 ClientExchangeFormat xformat):
424449 cdef Codec codec
425450 codec = Codec(oid)
426451 codec.init(name, schema, kind, CODEC_PY, format, xformat,
427- c_encoder, c_decoder, encoder, decoder,
452+ c_encoder, c_decoder, base_codec, encoder, decoder,
428453 None , None , None , None , 0 )
429454 return codec
430455
@@ -596,34 +621,43 @@ cdef class DataCodecConfig:
596621 self .declare_fallback_codec(oid, name, schema)
597622
598623 def add_python_codec (self , typeoid , typename , typeschema , typekind ,
599- encoder , decoder , format , xformat ):
624+ typeinfos , encoder , decoder , format , xformat ):
600625 cdef:
601- Codec core_codec
626+ Codec core_codec = None
602627 encode_func c_encoder = NULL
603628 decode_func c_decoder = NULL
629+ Codec base_codec = None
604630 uint32_t oid = pylong_as_oid(typeoid)
605631 bint codec_set = False
606632
607633 # Clear all previous overrides (this also clears type cache).
608634 self .remove_python_codec(typeoid, typename, typeschema)
609635
636+ if typeinfos:
637+ self .add_types(typeinfos)
638+
610639 if format == PG_FORMAT_ANY:
611640 formats = (PG_FORMAT_TEXT, PG_FORMAT_BINARY)
612641 else :
613642 formats = (format,)
614643
615644 for fmt in formats:
616645 if xformat == PG_XFORMAT_TUPLE:
617- core_codec = get_core_codec(oid, fmt, xformat)
618- if core_codec is None :
619- continue
620- c_encoder = core_codec.c_encoder
621- c_decoder = core_codec.c_decoder
646+ if typekind == " scalar" :
647+ core_codec = get_core_codec(oid, fmt, xformat)
648+ if core_codec is None :
649+ continue
650+ c_encoder = core_codec.c_encoder
651+ c_decoder = core_codec.c_decoder
652+ elif typekind == " composite" :
653+ base_codec = self .get_codec(oid, fmt)
654+ if base_codec is None :
655+ continue
622656
623657 self ._custom_type_codecs[typeoid, fmt] = \
624658 Codec.new_python_codec(oid, typename, typeschema, typekind,
625659 encoder, decoder, c_encoder, c_decoder,
626- fmt, xformat)
660+ base_codec, fmt, xformat)
627661 codec_set = True
628662
629663 if not codec_set:
@@ -829,7 +863,7 @@ cdef register_core_codec(uint32_t oid,
829863
830864 codec = Codec(oid)
831865 codec.init(name, ' pg_catalog' , kind, CODEC_C, format, xformat,
832- encode, decode, None , None , None , None , None , None , 0 )
866+ encode, decode, None , None , None , None , None , None , None , 0 )
833867 cpython.Py_INCREF(codec) # immortalize
834868
835869 if format == PG_FORMAT_BINARY:
@@ -853,7 +887,7 @@ cdef register_extra_codec(str name,
853887
854888 codec = Codec(INVALIDOID)
855889 codec.init(name, None , kind, CODEC_C, format, PG_XFORMAT_OBJECT,
856- encode, decode, None , None , None , None , None , None , 0 )
890+ encode, decode, None , None , None , None , None , None , None , 0 )
857891 EXTRA_CODECS[name, format] = codec
858892
859893
0 commit comments