Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PlanScan did not find a plan when using sql.Scanner with float4 column (v5) #1911

Closed
MattBrittan opened this issue Feb 16, 2024 · 1 comment
Labels

Comments

@MattBrittan
Copy link

MattBrittan commented Feb 16, 2024

Describe the bug
PlanScan did not find a plan error when scanning float into sql.Scanner struct. This works with v4 but fails on v5.

To Reproduce

Database setup:

CREATE TABLE pgxtest (
    testcol float4
);
insert into pgxtest (testcol) values (1.0)
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/jackc/pgx/v5"
)

func main() {
	conn, err := pgx.Connect(context.Background(), `postgres://username:password@localhost:5432/database_name`)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
		os.Exit(1)
	}
	defer conn.Close(context.Background())

	// This works OK
	var testVal int64
	err = conn.QueryRow(context.Background(), "select testcol from pgxtest").Scan(&testVal)
	if err != nil {
		fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
		os.Exit(1)
	}
	fmt.Println(testVal)

	// This does not
	var testVal2 scanner
	err = conn.QueryRow(context.Background(), "select testcol from pgxtest").Scan(&testVal2)
	if err != nil {
		fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err) // QueryRow failed: can't scan into dest[0]: PlanScan did not find a plan
		os.Exit(1)
	}
	fmt.Println(testVal2)

}

type scanner struct {
	val float64
}

func (s *scanner) Scan(src any) error {
	if b, ok := src.(float64); ok {
		s.val = b
                return nil
	}
	return fmt.Errorf("unsupported input %T", src)
}

Expected behavior

Expected that scanner.Scan would be called and passed an float64.

Actual behavior

Fails before Scan is called with error: QueryRow failed: can't scan into dest[0]: PlanScan did not find a plan

Version

  • go version go1.22.0 windows/amd64
  • PostgreSQL 15.5 on x86_64-pc-linux-musl, compiled by gcc (Alpine 13.2.1_git20231014) 13.2.1 20231014, 64-bit
  • github.com/jackc/pgx/v5 v5.5.3

Additional context

If I change to V4 (just change github.com/jackc/pgx/v5 to github.com/jackc/pgx/v4) then this runs as expected.

I've looked through the code and it appears that the issue is in pgtype/float4; in DecodeDatabaseSQLValue it passes a *float64 into codecScan which then calls Float4Codec.PlanScan but that only supports *float32 or Float64Scanner. I may be wrong about this as I'm not familiar with the code.

As a workaround I've added *float64 to (Float4Codec) PlanScan and this appears to work OK. Happy to submit a PR but suspect this may have been excluded intentionally? e.g.

case BinaryFormatCode:
		switch target.(type) {
		case *float32:
			return scanPlanBinaryFloat4ToFloat32{}
		case *float64:
			return scanPlanBinaryFloat4ToFloat64{}
		case Float64Scanner:
			return scanPlanBinaryFloat4ToFloat64Scanner{}
		case Int64Scanner:
			return scanPlanBinaryFloat4ToInt64Scanner{}
		case TextScanner:
			return scanPlanBinaryFloat4ToTextScanner{}
		}
MattBrittan added a commit to MattBrittan/pgx that referenced this issue Feb 17, 2024
…pport scanning

float4 using a `sql.Scanner` (previously this resulted in "did not find a plan" error)

closes jackc#1911
jackc added a commit that referenced this issue Feb 24, 2024
@jackc
Copy link
Owner

jackc commented Feb 24, 2024

It may be possible to fix it in (Float4Codec) PlanScan, but I think it is more direct to fix it in DecodeDatabaseSQLValue by scanning into a float32 that is converted to a float64 on return.

Fixed in 85f15c4.

@jackc jackc closed this as completed Feb 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants