diff --git a/doc.go b/doc.go index 3b0ac90b..4cd3861b 100644 --- a/doc.go +++ b/doc.go @@ -1,8 +1,9 @@ // Package pgx is a PostgreSQL database driver. /* -pgx provides lower level access to PostgreSQL than the standard database/sql. It remains as similar to the database/sql -interface as possible while providing better speed and access to PostgreSQL specific features. Import -github.com/jackc/pgx/v4/stdlib to use pgx as a database/sql compatible driver. +pgx provides a native PostgreSQL driver and can act as a database/sql driver. The native PostgreSQL interface is similar +to the database/sql interface while providing better speed and access to PostgreSQL specific features. Use +github.com/jackc/pgx/v5/stdlib to use pgx as a database/sql compatible driver. See that package's documentation for +details. Establishing a Connection @@ -32,7 +33,7 @@ CollectRows can be used collect all returned rows into a slice. if err != nil { return err } - // numbers => [1 2 3 4 5] + // numbers => [1 2 3 4 5] ForEachRow can be used to execute a callback function for every row. This is often easier than iterating over rows directly. @@ -66,127 +67,10 @@ Use Exec to execute a query that does not return a result set. return errors.New("No row found to delete") } -Base Type Mapping +PostgreSQL Data Types -pgx maps between all common base types directly between Go and PostgreSQL. In particular: - - Go PostgreSQL - ----------------------- - string varchar - text - - // Integers are automatically be converted to any other integer type if - // it can be done without overflow or underflow. - int8 - int16 smallint - int32 int - int64 bigint - int - uint8 - uint16 - uint32 - uint64 - uint - - // Floats are strict and do not automatically convert like integers. - float32 float4 - float64 float8 - - time.Time date - timestamp - timestamptz - - []byte bytea - - -Null Mapping - -pgx can map nulls in two ways. The first is package pgtype provides types that have a data field and a status field. -They work in a similar fashion to database/sql. The second is to use a pointer to a pointer. - - var foo pgtype.Varchar - var bar *string - err := conn.QueryRow("select foo, bar from widgets where id=$1", 42).Scan(&foo, &bar) - if err != nil { - return err - } - -Array Mapping - -pgx maps between int16, int32, int64, float32, float64, and string Go slices and the equivalent PostgreSQL array type. -Go slices of native types do not support nulls, so if a PostgreSQL array that contains a null is read into a native Go -slice an error will occur. The pgtype package includes many more array types for PostgreSQL types that do not directly -map to native Go types. - -JSON and JSONB Mapping - -pgx includes built-in support to marshal and unmarshal between Go types and the PostgreSQL JSON and JSONB. - -Inet and CIDR Mapping - -pgx converts netip.Prefix and netip.Addr to and from inet and cidr PostgreSQL types. - -Custom Type Support - -pgx includes support for the common data types like integers, floats, strings, dates, and times that have direct -mappings between Go and SQL. In addition, pgx uses the github.com/jackc/pgx/v5/pgtype library to support more types. See -documention for that library for instructions on how to implement custom types. - -See example_custom_type_test.go for an example of a custom type for the PostgreSQL point type. - -pgx also includes support for custom types implementing the database/sql.Scanner and database/sql/driver.Valuer -interfaces. - -If pgx does cannot natively encode a type and that type is a renamed type (e.g. type MyTime time.Time) pgx will attempt -to encode the underlying type. While this is usually desired behavior it can produce surprising behavior if one the -underlying type and the renamed type each implement database/sql interfaces and the other implements pgx interfaces. It -is recommended that this situation be avoided by implementing pgx interfaces on the renamed type. - -Composite types and row values - -Row values and composite types are represented as pgtype.Record -(https://pkg.go.dev/github.com/jackc/pgtype?tab=doc#Record). It is possible to get values of your custom type by -implementing DecodeBinary interface. Decoding into pgtype.Record first can simplify process by avoiding dealing with raw -protocol directly. - -For example: - - type MyType struct { - a int // NULL will cause decoding error - b *string // there can be NULL in this position in SQL - } - - func (t *MyType) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error { - r := pgtype.Record{ - Fields: []pgtype.Value{&pgtype.Int4{}, &pgtype.Text{}}, - } - - if err := r.DecodeBinary(ci, src); err != nil { - return err - } - - if r.Status != pgtype.Present { - return errors.New("BUG: decoding should not be called on NULL value") - } - - a := r.Fields[0].(*pgtype.Int4) - b := r.Fields[1].(*pgtype.Text) - - // type compatibility is checked by AssignTo - // only lossless assignments will succeed - if err := a.AssignTo(&t.a); err != nil { - return err - } - - // AssignTo also deals with null value handling - if err := b.AssignTo(&t.b); err != nil { - return err - } - return nil - } - - result := MyType{} - err := conn.QueryRow(context.Background(), "select row(1, 'foo'::text)", pgx.QueryResultFormats{pgx.BinaryFormatCode}).Scan(&r) +The package pgtype provides extensive and customizable support for converting Go values to and from PostgreSQL values +including array and composite types. See that package's documentation for details. Transactions diff --git a/pgtype/doc.go b/pgtype/doc.go index 9764aabf..62d73ed2 100644 --- a/pgtype/doc.go +++ b/pgtype/doc.go @@ -6,6 +6,53 @@ types already registered. Additional types can be registered with Map.RegisterTy Use Map.Scan and Map.Encode to decode PostgreSQL values to Go and encode Go values to PostgreSQL respectively. +Base Type Mapping + +pgtype maps between all common base types directly between Go and PostgreSQL. In particular: + + Go PostgreSQL + ----------------------- + string varchar + text + + // Integers are automatically be converted to any other integer type if + // it can be done without overflow or underflow. + int8 + int16 smallint + int32 int + int64 bigint + int + uint8 + uint16 + uint32 + uint64 + uint + + // Floats are strict and do not automatically convert like integers. + float32 float4 + float64 float8 + + time.Time date + timestamp + timestamptz + + netip.Addr inet + netip.Prefix cidr + + []byte bytea + +Null Values + +pgtype can map NULLs in two ways. The first is types that can directly represent NULL such as Int4. They work in a +similar fashion to database/sql. The second is to use a pointer to a pointer. + + var foo pgtype.Text + var bar *string + err := conn.QueryRow("select foo, bar from widgets where id=$1", 42).Scan(&foo, &bar) + if err != nil { + return err + } + JSON Support pgtype automatically marshals and unmarshals data from json and jsonb PostgreSQL types. @@ -23,7 +70,8 @@ CompositeIndexGetter. Enum Support -PostgreSQL enums can usually be treated as text. However, EnumCodec implements support for interning strings which can reduce memory usage. +PostgreSQL enums can usually be treated as text. However, EnumCodec implements support for interning strings which can +reduce memory usage. Array, Composite, and Enum Type Registration @@ -35,6 +83,8 @@ Generally, all Codecs will support interfaces that can be implemented to enable PointCodec can use any Go type that implements the PointScanner and PointValuer interfaces. So rather than use pgtype.Point and application can directly use its own point type with pgtype as long as it implements those interfaces. +See example_custom_type_test.go for an example of a custom type for the PostgreSQL point type. + Sometimes pgx supports a PostgreSQL type such as numeric but the Go type is in an external package that does not have pgx support such as github.com/shopspring/decimal. These types can be registered with pgtype with custom conversion logic. See https://github.com/jackc/pgx-shopspring-decimal and https://github.com/jackc/pgx-gofrs-uuid for a example @@ -51,6 +101,17 @@ Encoding Unknown Types pgtype works best when the OID of the PostgreSQL type is known. But in some cases such as using the simple protocol the OID is unknown. In this case Map.RegisterDefaultPgType can be used to register an assumed OID for a particular Go type. +Renamed Types + +If pgtype does not recognize a type and that type is a renamed simple type simple (e.g. type MyInt32 int32) pgtype acts +as if it is the underlying type. It currently cannot automatically detect the underlying type of renamed structs (eg.g. +type MyTime time.Time). + +Compatibility with database/sql + +pgtype also includes support for custom types implementing the database/sql.Scanner and database/sql/driver.Valuer +interfaces. + Overview of Scanning Implementation The first step is to use the OID to lookup the correct Codec. If the OID is unavailable, Map will try to find the OID diff --git a/stdlib/sql.go b/stdlib/sql.go index 8a24c4c5..fc0b0239 100644 --- a/stdlib/sql.go +++ b/stdlib/sql.go @@ -27,8 +27,8 @@ // // db.QueryRow("select * from users where id=$1", userID) // -// In Go 1.13 and above (*sql.Conn) Raw() can be used to get a *pgx.Conn from the standard database/sql.DB connection -// pool. This allows operations that use pgx specific functionality. +// (*sql.Conn) Raw() can be used to get a *pgx.Conn from the standard database/sql.DB connection pool. This allows +// operations that use pgx specific functionality. // // // Given db is a *sql.DB // conn, err := db.Conn(context.Background())