From: Daniele Varrazzo Date: Sat, 14 Nov 2020 02:24:43 +0000 (+0000) Subject: Trying to dump int as int8, added binary dumpers for int and float X-Git-Tag: 3.0.dev0~364 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c27647c0bb2bc1cd1efb9fe3c1d6ba95dbd92778;p=thirdparty%2Fpsycopg.git Trying to dump int as int8, added binary dumpers for int and float --- diff --git a/psycopg3/psycopg3/types/numeric.py b/psycopg3/psycopg3/types/numeric.py index 2773975e6..8281199e7 100644 --- a/psycopg3/psycopg3/types/numeric.py +++ b/psycopg3/psycopg3/types/numeric.py @@ -12,6 +12,7 @@ from ..oids import builtins from ..adapt import Dumper, Loader _PackInt = Callable[[int], bytes] +_PackFloat = Callable[[float], bytes] _UnpackInt = Callable[[bytes], Tuple[int]] _UnpackFloat = Callable[[bytes], Tuple[float]] @@ -19,6 +20,7 @@ _pack_int2 = cast(_PackInt, struct.Struct("!h").pack) _pack_int4 = cast(_PackInt, struct.Struct("!i").pack) _pack_uint4 = cast(_PackInt, struct.Struct("!I").pack) _pack_int8 = cast(_PackInt, struct.Struct("!q").pack) +_pack_float8 = cast(_PackFloat, struct.Struct("!d").pack) _unpack_int2 = cast(_UnpackInt, struct.Struct("!h").unpack) _unpack_int4 = cast(_UnpackInt, struct.Struct("!i").unpack) _unpack_uint4 = cast(_UnpackInt, struct.Struct("!I").unpack) @@ -66,18 +68,22 @@ class NumberDumper(Dumper): if value in self._special: return self._special[value] - return b" " + value if value.startswith(b"-") else value + return value if obj >= 0 else b" " + value @Dumper.text(int) class IntDumper(NumberDumper): - # We don't know the size of it, so we have to return a type big enough - oid = builtins["numeric"].oid + oid = builtins["int8"].oid + + +@Dumper.binary(int) +class IntBinaryDumper(IntDumper): + def dump(self, obj: int) -> bytes: + return _pack_int8(obj) @Dumper.text(float) class FloatDumper(NumberDumper): - oid = builtins["float8"].oid _special = { @@ -87,9 +93,14 @@ class FloatDumper(NumberDumper): } +@Dumper.binary(float) +class FloatBinaryDumper(NumberDumper): + def dump(self, obj: float) -> bytes: + return _pack_float8(obj) + + @Dumper.text(Decimal) class DecimalDumper(NumberDumper): - oid = builtins["numeric"].oid _special = { diff --git a/tests/types/test_numeric.py b/tests/types/test_numeric.py index a4bfe89ed..445b905dc 100644 --- a/tests/types/test_numeric.py +++ b/tests/types/test_numeric.py @@ -27,10 +27,12 @@ from psycopg3.types.numeric import FloatLoader (int(-(2 ** 63)), "'-9223372036854775808'::bigint"), ], ) -def test_dump_int(conn, val, expr): +@pytest.mark.parametrize("fmt_in", [Format.TEXT, Format.BINARY]) +def test_dump_int(conn, val, expr, fmt_in): + ph = "%s" if fmt_in == Format.TEXT else "%b" assert isinstance(val, int) cur = conn.cursor() - cur.execute(f"select {expr} = %s", (val,)) + cur.execute(f"select {expr} = {ph}", (val,)) assert cur.fetchone()[0] is True @@ -82,14 +84,6 @@ def test_quote_int(conn, val, expr): assert cur.fetchone() == (val, -val) -@pytest.mark.xfail -def test_dump_int_binary(): - # TODO: int binary adaptation (must choose the fitting int2,4,8) - tx = Transformer() - n = 1 - tx.get_dumper(n, Format.BINARY).dump(n) - - @pytest.mark.parametrize( "val, pgtype, want", [ @@ -146,10 +140,12 @@ def test_load_int(conn, val, pgtype, want, fmt_out): (float("-inf"), "'-Infinity'"), ], ) -def test_dump_float(conn, val, expr): +@pytest.mark.parametrize("fmt_in", [Format.TEXT, Format.BINARY]) +def test_dump_float(conn, val, expr, fmt_in): + ph = "%s" if fmt_in == Format.TEXT else "%b" assert isinstance(val, float) cur = conn.cursor() - cur.execute(f"select %s = {expr}::float8", (val,)) + cur.execute(f"select {ph} = {expr}::float8", (val,)) assert cur.fetchone()[0] is True @@ -208,14 +204,6 @@ def test_dump_float_approx(conn, val, expr): assert cur.fetchone()[0] is True -@pytest.mark.xfail -def test_dump_float_binary(): - # TODO: float binary adaptation - tx = Transformer() - n = 1.0 - tx.get_dumper(n, Format.BINARY).dump(n) - - @pytest.mark.parametrize( "val, pgtype, want", [