From: Daniele Varrazzo Date: Thu, 30 Sep 2021 00:56:41 +0000 (+0000) Subject: Add info about multirange types X-Git-Tag: 3.0~46^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2421e8a408e088c28578c76720d72dd98d59734f;p=thirdparty%2Fpsycopg.git Add info about multirange types --- diff --git a/psycopg/psycopg/_typeinfo.py b/psycopg/psycopg/_typeinfo.py index e0902bdc5..11438b121 100644 --- a/psycopg/psycopg/_typeinfo.py +++ b/psycopg/psycopg/_typeinfo.py @@ -82,17 +82,17 @@ class TypeInfo: if isinstance(name, Composable): name = name.as_string(conn) - cur = conn.cursor(binary=True, row_factory=dict_row) # This might result in a nested transaction. What we want is to leave # the function with the connection in the state we found (either idle # or intrans) try: with conn.transaction(): - cur.execute(cls._info_query, {"name": name}) + with conn.cursor(binary=True, row_factory=dict_row) as cur: + cur.execute(cls._get_info_query(conn), {"name": name}) + recs = cur.fetchall() except e.UndefinedObject: return None - recs = cur.fetchall() return cls._from_records(name, recs) @classmethod @@ -111,14 +111,18 @@ class TypeInfo: if isinstance(name, Composable): name = name.as_string(conn) - cur = conn.cursor(binary=True, row_factory=dict_row) try: async with conn.transaction(): - await cur.execute(cls._info_query, {"name": name}) + async with conn.cursor( + binary=True, row_factory=dict_row + ) as cur: + await cur.execute( + cls._get_info_query(conn), {"name": name} + ) + recs = await cur.fetchall() except e.UndefinedObject: return None - recs = await cur.fetchall() return cls._from_records(name, recs) @classmethod @@ -152,7 +156,11 @@ class TypeInfo: register_array(self, context) - _info_query = """\ + @classmethod + def _get_info_query( + cls, conn: "Union[Connection[Any], AsyncConnection[Any]]" + ) -> str: + return """\ SELECT typname AS name, oid, typarray AS array_oid, oid::regtype::text AS alt_name, typdelim AS delimiter @@ -175,7 +183,11 @@ class RangeInfo(TypeInfo): super().__init__(name, oid, array_oid) self.subtype_oid = subtype_oid - _info_query = """\ + @classmethod + def _get_info_query( + cls, conn: "Union[Connection[Any], AsyncConnection[Any]]" + ) -> str: + return """\ SELECT t.typname AS name, t.oid AS oid, t.typarray AS array_oid, r.rngsubtype AS subtype_oid FROM pg_type t @@ -184,11 +196,50 @@ WHERE t.oid = %(name)s::regtype """ def _added(self, registry: "TypesRegistry") -> None: - """Method called by the *registry* when the object is added there.""" # Map ranges subtypes to info registry._registry[RangeInfo, self.subtype_oid] = self +class MultirangeInfo(TypeInfo): + """Manage information about a multirange type.""" + + # TODO: expose to multirange module once added + # __module__ = "psycopg.types.multirange" + + def __init__( + self, + name: str, + oid: int, + array_oid: int, + range_oid: int, + subtype_oid: int, + ): + super().__init__(name, oid, array_oid) + self.range_oid = range_oid + self.subtype_oid = subtype_oid + + @classmethod + def _get_info_query( + cls, conn: "Union[Connection[Any], AsyncConnection[Any]]" + ) -> str: + if conn.info.server_version < 140000: + raise e.NotSupportedError( + "multirange types are only available from PostgreSQL 14" + ) + return """\ +SELECT t.typname AS name, t.oid AS oid, t.typarray AS array_oid, + r.rngtypid AS range_oid, r.rngsubtype AS subtype_oid +FROM pg_type t +JOIN pg_range r ON t.oid = r.rngmultitypid +WHERE t.oid = %(name)s::regtype +""" + + def _added(self, registry: "TypesRegistry") -> None: + # Map multiranges ranges and subtypes to info + registry._registry[MultirangeInfo, self.range_oid] = self + registry._registry[MultirangeInfo, self.subtype_oid] = self + + class CompositeInfo(TypeInfo): """Manage information about a composite type.""" @@ -208,7 +259,11 @@ class CompositeInfo(TypeInfo): # Will be set by register() if the `factory` is a type self.python_type: Optional[type] = None - _info_query = """\ + @classmethod + def _get_info_query( + cls, conn: "Union[Connection[Any], AsyncConnection[Any]]" + ) -> str: + return """\ SELECT t.typname AS name, t.oid AS oid, t.typarray AS array_oid, coalesce(a.fnames, '{}') AS field_names, diff --git a/psycopg/psycopg/postgres.py b/psycopg/psycopg/postgres.py index af052bcab..fe878a953 100644 --- a/psycopg/psycopg/postgres.py +++ b/psycopg/psycopg/postgres.py @@ -4,7 +4,7 @@ Types configuration specific to PostgreSQL. # Copyright (C) 2020-2021 The Psycopg Team -from ._typeinfo import TypeInfo, RangeInfo, TypesRegistry +from ._typeinfo import TypeInfo, RangeInfo, MultirangeInfo, TypesRegistry from .abc import AdaptContext from ._adapters_map import AdaptersMap @@ -17,7 +17,7 @@ adapters = AdaptersMap(types=types) # Use tools/update_oids.py to update this data. for t in [ # autogenerated: start - # Generated from PostgreSQL 13.4 + # Generated from PostgreSQL 14.0 TypeInfo("aclitem", 1033, 1034), TypeInfo("bit", 1560, 1561), TypeInfo("bool", 16, 1000, alt_name="boolean"), @@ -88,6 +88,24 @@ for t in [ RangeInfo("numrange", 3906, 3907, subtype_oid=1700), RangeInfo("tsrange", 3908, 3909, subtype_oid=1114), RangeInfo("tstzrange", 3910, 3911, subtype_oid=1184), + MultirangeInfo( + "datemultirange", 4535, 6155, range_oid=3912, subtype_oid=1082 + ), + MultirangeInfo( + "int4multirange", 4451, 6150, range_oid=3904, subtype_oid=23 + ), + MultirangeInfo( + "int8multirange", 4536, 6157, range_oid=3926, subtype_oid=20 + ), + MultirangeInfo( + "nummultirange", 4532, 6151, range_oid=3906, subtype_oid=1700 + ), + MultirangeInfo( + "tsmultirange", 4533, 6152, range_oid=3908, subtype_oid=1114 + ), + MultirangeInfo( + "tstzmultirange", 4534, 6153, range_oid=3910, subtype_oid=1184 + ), # autogenerated: end ]: types.add(t) diff --git a/psycopg_c/psycopg_c/_psycopg/oids.pxd b/psycopg_c/psycopg_c/_psycopg/oids.pxd index c4d933c68..1d0e4b677 100644 --- a/psycopg_c/psycopg_c/_psycopg/oids.pxd +++ b/psycopg_c/psycopg_c/_psycopg/oids.pxd @@ -11,7 +11,7 @@ cdef enum: # autogenerated: start - # Generated from PostgreSQL 13.4 + # Generated from PostgreSQL 14.0 ACLITEM_OID = 1033 BIT_OID = 1560 @@ -24,6 +24,7 @@ cdef enum: CIDR_OID = 650 CIRCLE_OID = 718 DATE_OID = 1082 + DATEMULTIRANGE_OID = 4535 DATERANGE_OID = 3912 FLOAT4_OID = 700 FLOAT8_OID = 701 @@ -32,8 +33,10 @@ cdef enum: INT2_OID = 21 INT2VECTOR_OID = 22 INT4_OID = 23 + INT4MULTIRANGE_OID = 4451 INT4RANGE_OID = 3904 INT8_OID = 20 + INT8MULTIRANGE_OID = 4536 INT8RANGE_OID = 3926 INTERVAL_OID = 1186 JSON_OID = 114 @@ -46,6 +49,7 @@ cdef enum: MONEY_OID = 790 NAME_OID = 19 NUMERIC_OID = 1700 + NUMMULTIRANGE_OID = 4532 NUMRANGE_OID = 3906 OID_OID = 26 OIDVECTOR_OID = 30 @@ -72,8 +76,10 @@ cdef enum: TIMESTAMP_OID = 1114 TIMESTAMPTZ_OID = 1184 TIMETZ_OID = 1266 + TSMULTIRANGE_OID = 4533 TSQUERY_OID = 3615 TSRANGE_OID = 3908 + TSTZMULTIRANGE_OID = 4534 TSTZRANGE_OID = 3910 TSVECTOR_OID = 3614 TXID_SNAPSHOT_OID = 2970 diff --git a/tools/update_oids.py b/tools/update_oids.py index d2caa93be..ec0345a6c 100755 --- a/tools/update_oids.py +++ b/tools/update_oids.py @@ -61,19 +61,33 @@ where order by typname """ +py_multiranges_sql = """ +select + format('MultirangeInfo(%L, %s, %s, range_oid=%s, subtype_oid=%s),', + typname, oid, typarray, rngtypid, rngsubtype) +from + pg_type t + join pg_range r on t.oid = rngmultitypid +where + oid < 10000 + and typtype = 'm' + and (typname !~ '^(_|pg_)' or typname = 'pg_lsn') +order by typname +""" + cython_oids_sql = """ select format('%s_OID = %s', upper(typname), oid) from pg_type where oid < 10000 - and (typtype = any('{b,r}') or typname = 'record') + and (typtype = any('{b,r,m}') or typname = 'record') and (typname !~ '^(_|pg_)' or typname = 'pg_lsn') order by typname """ def update_python_oids() -> None: - queries = [version_sql, py_types_sql, py_ranges_sql] + queries = [version_sql, py_types_sql, py_ranges_sql, py_multiranges_sql] fn = ROOT / "psycopg/psycopg/postgres.py" update_file(fn, queries) sp.check_call(["black", "-q", fn])