package pgximport ()/*buildLoadDerivedTypesSQL generates the correct query for retrieving type information. pgVersion: the major version of the PostgreSQL server typeNames: the names of the types to load. If nil, load all types.*/func ( int64, []string) string { := ( >= 14)varstringif == nil {// This should not occur; this will not return any types = "= ''" } else { = "= ANY($1::text[])" } := make([]string, 0, 10)// Each of the type names provided might be found in pg_class or pg_type. // Additionally, it may or may not include a schema portion. = append(, `WITH RECURSIVE-- find the OIDs in pg_class which match one of the provided type namesselected_classes(oid,reltype) AS ( -- this query uses the namespace search path, so will match type names without a schema prefix SELECT pg_class.oid, pg_class.reltype FROM pg_catalog.pg_class LEFT JOIN pg_catalog.pg_namespace n ON n.oid = pg_class.relnamespace WHERE pg_catalog.pg_table_is_visible(pg_class.oid) AND relname `, , `UNION ALL -- this query will only match type names which include the schema prefix SELECT pg_class.oid, pg_class.reltype FROM pg_class INNER JOIN pg_namespace ON (pg_class.relnamespace = pg_namespace.oid) WHERE nspname || '.' || relname `, , `),selected_types(oid) AS ( -- collect the OIDs from pg_types which correspond to the selected classes SELECT reltype AS oid FROM selected_classesUNION ALL -- as well as any other type names which match our criteria SELECT pg_type.oid FROM pg_type LEFT OUTER JOIN pg_namespace ON (pg_type.typnamespace = pg_namespace.oid) WHERE typname `, , ` OR nspname || '.' || typname `, , `),-- this builds a parent/child mapping of objects, allowing us to know-- all the child (ie: dependent) types that a parent (type) requires-- As can be seen, there are 3 ways this can occur (the last of which-- is due to being a composite class, where the composite fields are children)pc(parent, child) AS ( SELECT parent.oid, parent.typelem FROM pg_type parent WHERE parent.typtype = 'b' AND parent.typelem != 0UNION ALL SELECT parent.oid, parent.typbasetype FROM pg_type parent WHERE parent.typtypmod = -1 AND parent.typbasetype != 0UNION ALL SELECT pg_type.oid, atttypid FROM pg_attribute INNER JOIN pg_class ON (pg_class.oid = pg_attribute.attrelid) INNER JOIN pg_type ON (pg_type.oid = pg_class.reltype) WHERE NOT attisdropped AND attnum > 0),-- Now construct a recursive query which includes a 'depth' element.-- This is used to ensure that the "youngest" children are registered before-- their parents.relationships(parent, child, depth) AS ( SELECT DISTINCT 0::OID, selected_types.oid, 0 FROM selected_typesUNION ALL SELECT pg_type.oid AS parent, pg_attribute.atttypid AS child, 1 FROM selected_classes c inner join pg_type ON (c.reltype = pg_type.oid) inner join pg_attribute on (c.oid = pg_attribute.attrelid)UNION ALL SELECT pc.parent, pc.child, relationships.depth + 1 FROM pc INNER JOIN relationships ON (pc.parent = relationships.child)),-- composite fields need to be encapsulated as a couple of arrays to provide the required information for registrationcomposite AS ( SELECT pg_type.oid, ARRAY_AGG(attname ORDER BY attnum) AS attnames, ARRAY_AGG(atttypid ORDER BY ATTNUM) AS atttypids FROM pg_attribute INNER JOIN pg_class ON (pg_class.oid = pg_attribute.attrelid) INNER JOIN pg_type ON (pg_type.oid = pg_class.reltype) WHERE NOT attisdropped AND attnum > 0 GROUP BY pg_type.oid)-- Bring together this information, showing all the information which might possibly be required-- to complete the registration, applying filters to only show the items which relate to the selected-- types/classes.SELECT typname, pg_namespace.nspname, typtype, typbasetype, typelem, pg_type.oid,`)if { = append(, ` COALESCE(multirange.rngtypid, 0) AS rngtypid,`) } else { = append(, ` 0 AS rngtypid,`) } = append(, ` COALESCE(pg_range.rngsubtype, 0) AS rngsubtype, attnames, atttypids FROM relationships INNER JOIN pg_type ON (pg_type.oid = relationships.child) LEFT OUTER JOIN pg_range ON (pg_type.oid = pg_range.rngtypid)`)if { = append(, ` LEFT OUTER JOIN pg_range multirange ON (pg_type.oid = multirange.rngmultitypid)`) } = append(, ` LEFT OUTER JOIN composite USING (oid) LEFT OUTER JOIN pg_namespace ON (pg_type.typnamespace = pg_namespace.oid) WHERE NOT (typtype = 'b' AND typelem = 0)`) = append(, ` GROUP BY typname, pg_namespace.nspname, typtype, typbasetype, typelem, pg_type.oid, pg_range.rngsubtype,`)if { = append(, ` multirange.rngtypid,`) } = append(, ` attnames, atttypids ORDER BY MAX(depth) desc, typname;`)returnstrings.Join(, "")}typederivedTypeInfostruct {Oid, Typbasetype, Typelem, Rngsubtype, Rngtypiduint32TypeName, Typtype, NspNamestringAttnames []stringAtttypids []uint32}// LoadTypes performs a single (complex) query, returning all the required// information to register the named types, as well as any other types directly// or indirectly required to complete the registration.// The result of this call can be passed into RegisterTypes to complete the process.func ( *Conn) ( context.Context, []string) ([]*pgtype.Type, error) { := .TypeMap()iflen() == 0 {returnnil, fmt.Errorf("No type names were supplied.") }// Disregard server version errors. This will result in // the SQL not support recent structures such as multirange , := serverVersion() := buildLoadDerivedTypesSQL(, ) , := .Query(, , QueryResultFormats{TextFormatCode}, )if != nil {returnnil, fmt.Errorf("While generating load types query: %w", ) }defer .Close() := make([]*pgtype.Type, 0, 100)for .Next() { := derivedTypeInfo{} = .Scan(&.TypeName, &.NspName, &.Typtype, &.Typbasetype, &.Typelem, &.Oid, &.Rngtypid, &.Rngsubtype, &.Attnames, &.Atttypids)if != nil {returnnil, fmt.Errorf("While scanning type information: %w", ) }var *pgtype.Typeswitch .Typtype {case"b": // array , := .TypeForOID(.Typelem)if ! {returnnil, fmt.Errorf("Array element OID %v not registered while loading pgtype %q", .Typelem, .TypeName) } = &pgtype.Type{Name: .TypeName, OID: .Oid, Codec: &pgtype.ArrayCodec{ElementType: }}case"c": // compositevar []pgtype.CompositeCodecFieldfor , := range .Attnames { , := .TypeForOID(.Atttypids[])if ! {returnnil, fmt.Errorf("Unknown field for composite type %q: field %q (OID %v) is not already registered.", .TypeName, , .Atttypids[]) } = append(, pgtype.CompositeCodecField{Name: , Type: }) } = &pgtype.Type{Name: .TypeName, OID: .Oid, Codec: &pgtype.CompositeCodec{Fields: }}case"d": // domain , := .TypeForOID(.Typbasetype)if ! {returnnil, fmt.Errorf("Domain base type OID %v was not already registered, needed for %q", .Typbasetype, .TypeName) } = &pgtype.Type{Name: .TypeName, OID: .Oid, Codec: .Codec}case"e": // enum = &pgtype.Type{Name: .TypeName, OID: .Oid, Codec: &pgtype.EnumCodec{}}case"r": // range , := .TypeForOID(.Rngsubtype)if ! {returnnil, fmt.Errorf("Range element OID %v was not already registered, needed for %q", .Rngsubtype, .TypeName) } = &pgtype.Type{Name: .TypeName, OID: .Oid, Codec: &pgtype.RangeCodec{ElementType: }}case"m": // multirange , := .TypeForOID(.Rngtypid)if ! {returnnil, fmt.Errorf("Multirange element OID %v was not already registered, needed for %q", .Rngtypid, .TypeName) } = &pgtype.Type{Name: .TypeName, OID: .Oid, Codec: &pgtype.MultirangeCodec{ElementType: }}default:returnnil, fmt.Errorf("Unknown typtype %q was found while registering %q", .Typtype, .TypeName) }// the type_ is impossible to be null .RegisterType()if .NspName != "" { := &pgtype.Type{Name: .NspName + "." + .Name, OID: .OID, Codec: .Codec} .RegisterType() = append(, ) } = append(, ) }return , nil}// serverVersion returns the postgresql server version.func ( *Conn) (int64, error) { := .PgConn().ParameterStatus("server_version") = regexp.MustCompile(`^[0-9]+`).FindString()// if not PostgreSQL do nothingif == "" {return0, fmt.Errorf("Cannot identify server version in %q", ) } , := strconv.ParseInt(, 10, 64)if != nil {return0, fmt.Errorf("postgres version parsing failed: %w", ) }return , nil}
The pages are generated with Goldsv0.7.6. (GOOS=linux GOARCH=amd64)