pgx icon indicating copy to clipboard operation
pgx copied to clipboard

Since v5 pgx.ScanRow cannot scan null::INTEGER to sql.NullInt64

Open pierrick-martin-dev opened this issue 1 year ago • 0 comments

Describe the bug It seems since v5, pgx.ScanRow cannot scan a null::INTERGER to a sql.NullInt64. In v4, I confirm It worked.

To Reproduce Both function do the same thing. Querying and scanning a null::INTEGER

package main

import (
	"context"
	"database/sql"
	"fmt"

	"github.com/jackc/pgx/v5"
	"github.com/jackc/pgx/v5/pgconn"
	"github.com/jackc/pgx/v5/pgtype"

	pgconnV4 "github.com/jackc/pgconn"
	pgtypeV4 "github.com/jackc/pgtype"
	pgxV4 "github.com/jackc/pgx/v4"
)

const SQL = `SELECT null::INTEGER AS test`

func main() {

	if v, err := v4(); err != nil {
		fmt.Printf("Error in v4: %v\n", err)
	} else {
		fmt.Printf("V4 successful v = %v\n", v)
	}

	if v, err := v5(); err != nil {
		fmt.Printf("Error in v5: %v\n", err)
	} else {
		fmt.Printf("V5 successful v = %v\n", v)
	}
}

func v4() (sql.NullInt64, error) {
	pgconn, err := pgconnV4.Connect(context.Background(), "")
	if err != nil {
		return sql.NullInt64{}, fmt.Errorf("pgconnV4.Connect(): %w", err)
	}
	defer pgconn.Close(context.Background())

	result := pgconn.Exec(context.Background(), SQL)

	r, err := result.ReadAll()
	if err != nil {
		return sql.NullInt64{}, fmt.Errorf("result.ReadAll(): %w", err)
	}

	v := sql.NullInt64{}

	fmt.Printf("r[0].Rows[0][0] = %v\n", r[0].Rows[0][0])

	if err := pgxV4.ScanRow(pgtypeV4.NewConnInfo(), r[0].FieldDescriptions, r[0].Rows[0], &v); err != nil {
		return sql.NullInt64{}, fmt.Errorf("pgxV4.ScanRow(): %w", err)
	}

	return v, nil
}

func v5() (sql.NullInt64, error) {
	pgConn, err := pgconn.Connect(context.Background(), "")
	if err != nil {
		return sql.NullInt64{}, fmt.Errorf("pgconn.Connect(): %w", err)
	}
	defer pgConn.Close(context.Background())

	result := pgConn.Exec(context.Background(), SQL)

	r, err := result.ReadAll()
	if err != nil {
		return sql.NullInt64{}, fmt.Errorf("result.ReadAll(): %w", err)
	}

	v := sql.NullInt64{}

	fmt.Printf("r[0].Rows[0][0] = %v\n", r[0].Rows[0][0])

	if err := pgx.ScanRow(pgtype.NewMap(), r[0].FieldDescriptions, r[0].Rows[0], &v); err != nil {
		return sql.NullInt64{}, fmt.Errorf("pgxV4.ScanRow(): %w", err)
	}

	return v, nil
}

Expected behavior Reading the CHANGELOG, I can't see anything about that behaviour.

Actual behavior In v5 an error occurs:

pgxV4.ScanRow(): can't scan into dest[0]: strconv.ParseInt: parsing "": invalid syntax

Version

  • Go: go version go1.22.2 linux/amd64
  • PostgreSQL: PostgreSQL 15.4 (Debian 15.4-2.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
  • pgx: github.com/jackc/pgx/v4 v4.18.3 github.com/jackc/pgx/v5 v5.5.5

Additional context func (n *NullInt64) Scan(value any) seems to not be called. Want to know if I missed something somewhere between v4 and v5 or I can investigate further more.

I also tried to use a pgtype.Int8 same result.

func (m *Map) PlanScan(oid uint32, formatCode int16, target any) ScanPlan seems to have changed a lot between v4 and v5.

Thanks for your time.

pierrick-martin-dev avatar Apr 13 '24 22:04 pierrick-martin-dev