diff options
author | 2025-03-09 17:47:56 +0100 | |
---|---|---|
committer | 2025-03-10 01:59:49 +0100 | |
commit | 3ac1ee16f377d31a0fb80c8dae28b6239ac4229e (patch) | |
tree | f61faa581feaaeaba2542b9f2b8234a590684413 /vendor/github.com/jackc/pgx/v5/stdlib/sql.go | |
parent | [chore] update URLs to forked source (diff) | |
download | gotosocial-3ac1ee16f377d31a0fb80c8dae28b6239ac4229e.tar.xz |
[chore] remove vendor
Diffstat (limited to 'vendor/github.com/jackc/pgx/v5/stdlib/sql.go')
-rw-r--r-- | vendor/github.com/jackc/pgx/v5/stdlib/sql.go | 881 |
1 files changed, 0 insertions, 881 deletions
diff --git a/vendor/github.com/jackc/pgx/v5/stdlib/sql.go b/vendor/github.com/jackc/pgx/v5/stdlib/sql.go deleted file mode 100644 index c1d00ab40..000000000 --- a/vendor/github.com/jackc/pgx/v5/stdlib/sql.go +++ /dev/null @@ -1,881 +0,0 @@ -// Package stdlib is the compatibility layer from pgx to database/sql. -// -// A database/sql connection can be established through sql.Open. -// -// db, err := sql.Open("pgx", "postgres://pgx_md5:secret@localhost:5432/pgx_test?sslmode=disable") -// if err != nil { -// return err -// } -// -// Or from a keyword/value string. -// -// db, err := sql.Open("pgx", "user=postgres password=secret host=localhost port=5432 database=pgx_test sslmode=disable") -// if err != nil { -// return err -// } -// -// Or from a *pgxpool.Pool. -// -// pool, err := pgxpool.New(context.Background(), os.Getenv("DATABASE_URL")) -// if err != nil { -// return err -// } -// -// db := stdlib.OpenDBFromPool(pool) -// -// Or a pgx.ConnConfig can be used to set configuration not accessible via connection string. In this case the -// pgx.ConnConfig must first be registered with the driver. This registration returns a connection string which is used -// with sql.Open. -// -// connConfig, _ := pgx.ParseConfig(os.Getenv("DATABASE_URL")) -// connConfig.Tracer = &tracelog.TraceLog{Logger: myLogger, LogLevel: tracelog.LogLevelInfo} -// connStr := stdlib.RegisterConnConfig(connConfig) -// db, _ := sql.Open("pgx", connStr) -// -// pgx uses standard PostgreSQL positional parameters in queries. e.g. $1, $2. It does not support named parameters. -// -// db.QueryRow("select * from users where id=$1", userID) -// -// (*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()) -// if err != nil { -// // handle error from acquiring connection from DB pool -// } -// -// err = conn.Raw(func(driverConn any) error { -// conn := driverConn.(*stdlib.Conn).Conn() // conn is a *pgx.Conn -// // Do pgx specific stuff with conn -// conn.CopyFrom(...) -// return nil -// }) -// if err != nil { -// // handle error that occurred while using *pgx.Conn -// } -// -// # PostgreSQL Specific Data Types -// -// The pgtype package provides support for PostgreSQL specific types. *pgtype.Map.SQLScanner is an adapter that makes -// these types usable as a sql.Scanner. -// -// m := pgtype.NewMap() -// var a []int64 -// err := db.QueryRow("select '{1,2,3}'::bigint[]").Scan(m.SQLScanner(&a)) -package stdlib - -import ( - "context" - "database/sql" - "database/sql/driver" - "errors" - "fmt" - "io" - "math" - "math/rand" - "reflect" - "slices" - "strconv" - "strings" - "sync" - "time" - - "github.com/jackc/pgx/v5" - "github.com/jackc/pgx/v5/pgconn" - "github.com/jackc/pgx/v5/pgtype" - "github.com/jackc/pgx/v5/pgxpool" -) - -// Only intrinsic types should be binary format with database/sql. -var databaseSQLResultFormats pgx.QueryResultFormatsByOID - -var pgxDriver *Driver - -func init() { - pgxDriver = &Driver{ - configs: make(map[string]*pgx.ConnConfig), - } - - // if pgx driver was already registered by different pgx major version then we - // skip registration under the default name. - if !slices.Contains(sql.Drivers(), "pgx") { - sql.Register("pgx", pgxDriver) - } - sql.Register("pgx/v5", pgxDriver) - - databaseSQLResultFormats = pgx.QueryResultFormatsByOID{ - pgtype.BoolOID: 1, - pgtype.ByteaOID: 1, - pgtype.CIDOID: 1, - pgtype.DateOID: 1, - pgtype.Float4OID: 1, - pgtype.Float8OID: 1, - pgtype.Int2OID: 1, - pgtype.Int4OID: 1, - pgtype.Int8OID: 1, - pgtype.OIDOID: 1, - pgtype.TimestampOID: 1, - pgtype.TimestamptzOID: 1, - pgtype.XIDOID: 1, - } -} - -// OptionOpenDB options for configuring the driver when opening a new db pool. -type OptionOpenDB func(*connector) - -// OptionBeforeConnect provides a callback for before connect. It is passed a shallow copy of the ConnConfig that will -// be used to connect, so only its immediate members should be modified. Used only if db is opened with *pgx.ConnConfig. -func OptionBeforeConnect(bc func(context.Context, *pgx.ConnConfig) error) OptionOpenDB { - return func(dc *connector) { - dc.BeforeConnect = bc - } -} - -// OptionAfterConnect provides a callback for after connect. Used only if db is opened with *pgx.ConnConfig. -func OptionAfterConnect(ac func(context.Context, *pgx.Conn) error) OptionOpenDB { - return func(dc *connector) { - dc.AfterConnect = ac - } -} - -// OptionResetSession provides a callback that can be used to add custom logic prior to executing a query on the -// connection if the connection has been used before. -// If ResetSessionFunc returns ErrBadConn error the connection will be discarded. -func OptionResetSession(rs func(context.Context, *pgx.Conn) error) OptionOpenDB { - return func(dc *connector) { - dc.ResetSession = rs - } -} - -// RandomizeHostOrderFunc is a BeforeConnect hook that randomizes the host order in the provided connConfig, so that a -// new host becomes primary each time. This is useful to distribute connections for multi-master databases like -// CockroachDB. If you use this you likely should set https://golang.org/pkg/database/sql/#DB.SetConnMaxLifetime as well -// to ensure that connections are periodically rebalanced across your nodes. -func RandomizeHostOrderFunc(ctx context.Context, connConfig *pgx.ConnConfig) error { - if len(connConfig.Fallbacks) == 0 { - return nil - } - - newFallbacks := append([]*pgconn.FallbackConfig{{ - Host: connConfig.Host, - Port: connConfig.Port, - TLSConfig: connConfig.TLSConfig, - }}, connConfig.Fallbacks...) - - rand.Shuffle(len(newFallbacks), func(i, j int) { - newFallbacks[i], newFallbacks[j] = newFallbacks[j], newFallbacks[i] - }) - - // Use the one that sorted last as the primary and keep the rest as the fallbacks - newPrimary := newFallbacks[len(newFallbacks)-1] - connConfig.Host = newPrimary.Host - connConfig.Port = newPrimary.Port - connConfig.TLSConfig = newPrimary.TLSConfig - connConfig.Fallbacks = newFallbacks[:len(newFallbacks)-1] - return nil -} - -func GetConnector(config pgx.ConnConfig, opts ...OptionOpenDB) driver.Connector { - c := connector{ - ConnConfig: config, - BeforeConnect: func(context.Context, *pgx.ConnConfig) error { return nil }, // noop before connect by default - AfterConnect: func(context.Context, *pgx.Conn) error { return nil }, // noop after connect by default - ResetSession: func(context.Context, *pgx.Conn) error { return nil }, // noop reset session by default - driver: pgxDriver, - } - - for _, opt := range opts { - opt(&c) - } - return c -} - -// GetPoolConnector creates a new driver.Connector from the given *pgxpool.Pool. By using this be sure to set the -// maximum idle connections of the *sql.DB created with this connector to zero since they must be managed from the -// *pgxpool.Pool. This is required to avoid acquiring all the connections from the pgxpool and starving any direct -// users of the pgxpool. -func GetPoolConnector(pool *pgxpool.Pool, opts ...OptionOpenDB) driver.Connector { - c := connector{ - pool: pool, - ResetSession: func(context.Context, *pgx.Conn) error { return nil }, // noop reset session by default - driver: pgxDriver, - } - - for _, opt := range opts { - opt(&c) - } - - return c -} - -func OpenDB(config pgx.ConnConfig, opts ...OptionOpenDB) *sql.DB { - c := GetConnector(config, opts...) - return sql.OpenDB(c) -} - -// OpenDBFromPool creates a new *sql.DB from the given *pgxpool.Pool. Note that this method automatically sets the -// maximum number of idle connections in *sql.DB to zero, since they must be managed from the *pgxpool.Pool. This is -// required to avoid acquiring all the connections from the pgxpool and starving any direct users of the pgxpool. -func OpenDBFromPool(pool *pgxpool.Pool, opts ...OptionOpenDB) *sql.DB { - c := GetPoolConnector(pool, opts...) - db := sql.OpenDB(c) - db.SetMaxIdleConns(0) - return db -} - -type connector struct { - pgx.ConnConfig - pool *pgxpool.Pool - BeforeConnect func(context.Context, *pgx.ConnConfig) error // function to call before creation of every new connection - AfterConnect func(context.Context, *pgx.Conn) error // function to call after creation of every new connection - ResetSession func(context.Context, *pgx.Conn) error // function is called before a connection is reused - driver *Driver -} - -// Connect implement driver.Connector interface -func (c connector) Connect(ctx context.Context) (driver.Conn, error) { - var ( - connConfig pgx.ConnConfig - conn *pgx.Conn - close func(context.Context) error - err error - ) - - if c.pool == nil { - // Create a shallow copy of the config, so that BeforeConnect can safely modify it - connConfig = c.ConnConfig - - if err = c.BeforeConnect(ctx, &connConfig); err != nil { - return nil, err - } - - if conn, err = pgx.ConnectConfig(ctx, &connConfig); err != nil { - return nil, err - } - - if err = c.AfterConnect(ctx, conn); err != nil { - return nil, err - } - - close = conn.Close - } else { - var pconn *pgxpool.Conn - - pconn, err = c.pool.Acquire(ctx) - if err != nil { - return nil, err - } - - conn = pconn.Conn() - - close = func(_ context.Context) error { - pconn.Release() - return nil - } - } - - return &Conn{ - conn: conn, - close: close, - driver: c.driver, - connConfig: connConfig, - resetSessionFunc: c.ResetSession, - psRefCounts: make(map[*pgconn.StatementDescription]int), - }, nil -} - -// Driver implement driver.Connector interface -func (c connector) Driver() driver.Driver { - return c.driver -} - -// GetDefaultDriver returns the driver initialized in the init function -// and used when the pgx driver is registered. -func GetDefaultDriver() driver.Driver { - return pgxDriver -} - -type Driver struct { - configMutex sync.Mutex - configs map[string]*pgx.ConnConfig - sequence int -} - -func (d *Driver) Open(name string) (driver.Conn, error) { - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) // Ensure eventual timeout - defer cancel() - - connector, err := d.OpenConnector(name) - if err != nil { - return nil, err - } - return connector.Connect(ctx) -} - -func (d *Driver) OpenConnector(name string) (driver.Connector, error) { - return &driverConnector{driver: d, name: name}, nil -} - -func (d *Driver) registerConnConfig(c *pgx.ConnConfig) string { - d.configMutex.Lock() - connStr := fmt.Sprintf("registeredConnConfig%d", d.sequence) - d.sequence++ - d.configs[connStr] = c - d.configMutex.Unlock() - return connStr -} - -func (d *Driver) unregisterConnConfig(connStr string) { - d.configMutex.Lock() - delete(d.configs, connStr) - d.configMutex.Unlock() -} - -type driverConnector struct { - driver *Driver - name string -} - -func (dc *driverConnector) Connect(ctx context.Context) (driver.Conn, error) { - var connConfig *pgx.ConnConfig - - dc.driver.configMutex.Lock() - connConfig = dc.driver.configs[dc.name] - dc.driver.configMutex.Unlock() - - if connConfig == nil { - var err error - connConfig, err = pgx.ParseConfig(dc.name) - if err != nil { - return nil, err - } - } - - conn, err := pgx.ConnectConfig(ctx, connConfig) - if err != nil { - return nil, err - } - - c := &Conn{ - conn: conn, - close: conn.Close, - driver: dc.driver, - connConfig: *connConfig, - resetSessionFunc: func(context.Context, *pgx.Conn) error { return nil }, - psRefCounts: make(map[*pgconn.StatementDescription]int), - } - - return c, nil -} - -func (dc *driverConnector) Driver() driver.Driver { - return dc.driver -} - -// RegisterConnConfig registers a ConnConfig and returns the connection string to use with Open. -func RegisterConnConfig(c *pgx.ConnConfig) string { - return pgxDriver.registerConnConfig(c) -} - -// UnregisterConnConfig removes the ConnConfig registration for connStr. -func UnregisterConnConfig(connStr string) { - pgxDriver.unregisterConnConfig(connStr) -} - -type Conn struct { - conn *pgx.Conn - close func(context.Context) error - driver *Driver - connConfig pgx.ConnConfig - resetSessionFunc func(context.Context, *pgx.Conn) error // Function is called before a connection is reused - lastResetSessionTime time.Time - - // psRefCounts contains reference counts for prepared statements. Prepare uses the underlying pgx logic to generate - // deterministic statement names from the statement text. If this query has already been prepared then the existing - // *pgconn.StatementDescription will be returned. However, this means that if Close is called on the returned Stmt - // then the underlying prepared statement will be closed even when the underlying prepared statement is still in use - // by another database/sql Stmt. To prevent this psRefCounts keeps track of how many database/sql statements are using - // the same underlying statement and only closes the underlying statement when the reference count reaches 0. - psRefCounts map[*pgconn.StatementDescription]int -} - -// Conn returns the underlying *pgx.Conn -func (c *Conn) Conn() *pgx.Conn { - return c.conn -} - -func (c *Conn) Prepare(query string) (driver.Stmt, error) { - return c.PrepareContext(context.Background(), query) -} - -func (c *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { - if c.conn.IsClosed() { - return nil, driver.ErrBadConn - } - - sd, err := c.conn.Prepare(ctx, query, query) - if err != nil { - return nil, err - } - c.psRefCounts[sd]++ - - return &Stmt{sd: sd, conn: c}, nil -} - -func (c *Conn) Close() error { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - return c.close(ctx) -} - -func (c *Conn) Begin() (driver.Tx, error) { - return c.BeginTx(context.Background(), driver.TxOptions{}) -} - -func (c *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { - if c.conn.IsClosed() { - return nil, driver.ErrBadConn - } - - var pgxOpts pgx.TxOptions - switch sql.IsolationLevel(opts.Isolation) { - case sql.LevelDefault: - case sql.LevelReadUncommitted: - pgxOpts.IsoLevel = pgx.ReadUncommitted - case sql.LevelReadCommitted: - pgxOpts.IsoLevel = pgx.ReadCommitted - case sql.LevelRepeatableRead, sql.LevelSnapshot: - pgxOpts.IsoLevel = pgx.RepeatableRead - case sql.LevelSerializable: - pgxOpts.IsoLevel = pgx.Serializable - default: - return nil, fmt.Errorf("unsupported isolation: %v", opts.Isolation) - } - - if opts.ReadOnly { - pgxOpts.AccessMode = pgx.ReadOnly - } - - tx, err := c.conn.BeginTx(ctx, pgxOpts) - if err != nil { - return nil, err - } - - return wrapTx{ctx: ctx, tx: tx}, nil -} - -func (c *Conn) ExecContext(ctx context.Context, query string, argsV []driver.NamedValue) (driver.Result, error) { - if c.conn.IsClosed() { - return nil, driver.ErrBadConn - } - - args := namedValueToInterface(argsV) - - commandTag, err := c.conn.Exec(ctx, query, args...) - // if we got a network error before we had a chance to send the query, retry - if err != nil { - if pgconn.SafeToRetry(err) { - return nil, driver.ErrBadConn - } - } - return driver.RowsAffected(commandTag.RowsAffected()), err -} - -func (c *Conn) QueryContext(ctx context.Context, query string, argsV []driver.NamedValue) (driver.Rows, error) { - if c.conn.IsClosed() { - return nil, driver.ErrBadConn - } - - args := []any{databaseSQLResultFormats} - args = append(args, namedValueToInterface(argsV)...) - - rows, err := c.conn.Query(ctx, query, args...) - if err != nil { - if pgconn.SafeToRetry(err) { - return nil, driver.ErrBadConn - } - return nil, err - } - - // Preload first row because otherwise we won't know what columns are available when database/sql asks. - more := rows.Next() - if err = rows.Err(); err != nil { - rows.Close() - return nil, err - } - return &Rows{conn: c, rows: rows, skipNext: true, skipNextMore: more}, nil -} - -func (c *Conn) Ping(ctx context.Context) error { - if c.conn.IsClosed() { - return driver.ErrBadConn - } - - err := c.conn.Ping(ctx) - if err != nil { - // A Ping failure implies some sort of fatal state. The connection is almost certainly already closed by the - // failure, but manually close it just to be sure. - c.Close() - return driver.ErrBadConn - } - - return nil -} - -func (c *Conn) CheckNamedValue(*driver.NamedValue) error { - // Underlying pgx supports sql.Scanner and driver.Valuer interfaces natively. So everything can be passed through directly. - return nil -} - -func (c *Conn) ResetSession(ctx context.Context) error { - if c.conn.IsClosed() { - return driver.ErrBadConn - } - - now := time.Now() - if now.Sub(c.lastResetSessionTime) > time.Second { - if err := c.conn.PgConn().Ping(ctx); err != nil { - return driver.ErrBadConn - } - } - c.lastResetSessionTime = now - - return c.resetSessionFunc(ctx, c.conn) -} - -type Stmt struct { - sd *pgconn.StatementDescription - conn *Conn -} - -func (s *Stmt) Close() error { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - - refCount := s.conn.psRefCounts[s.sd] - if refCount == 1 { - delete(s.conn.psRefCounts, s.sd) - } else { - s.conn.psRefCounts[s.sd]-- - return nil - } - - return s.conn.conn.Deallocate(ctx, s.sd.SQL) -} - -func (s *Stmt) NumInput() int { - return len(s.sd.ParamOIDs) -} - -func (s *Stmt) Exec(argsV []driver.Value) (driver.Result, error) { - return nil, errors.New("Stmt.Exec deprecated and not implemented") -} - -func (s *Stmt) ExecContext(ctx context.Context, argsV []driver.NamedValue) (driver.Result, error) { - return s.conn.ExecContext(ctx, s.sd.SQL, argsV) -} - -func (s *Stmt) Query(argsV []driver.Value) (driver.Rows, error) { - return nil, errors.New("Stmt.Query deprecated and not implemented") -} - -func (s *Stmt) QueryContext(ctx context.Context, argsV []driver.NamedValue) (driver.Rows, error) { - return s.conn.QueryContext(ctx, s.sd.SQL, argsV) -} - -type rowValueFunc func(src []byte) (driver.Value, error) - -type Rows struct { - conn *Conn - rows pgx.Rows - valueFuncs []rowValueFunc - skipNext bool - skipNextMore bool - - columnNames []string -} - -func (r *Rows) Columns() []string { - if r.columnNames == nil { - fields := r.rows.FieldDescriptions() - r.columnNames = make([]string, len(fields)) - for i, fd := range fields { - r.columnNames[i] = string(fd.Name) - } - } - - return r.columnNames -} - -// ColumnTypeDatabaseTypeName returns the database system type name. If the name is unknown the OID is returned. -func (r *Rows) ColumnTypeDatabaseTypeName(index int) string { - if dt, ok := r.conn.conn.TypeMap().TypeForOID(r.rows.FieldDescriptions()[index].DataTypeOID); ok { - return strings.ToUpper(dt.Name) - } - - return strconv.FormatInt(int64(r.rows.FieldDescriptions()[index].DataTypeOID), 10) -} - -const varHeaderSize = 4 - -// ColumnTypeLength returns the length of the column type if the column is a -// variable length type. If the column is not a variable length type ok -// should return false. -func (r *Rows) ColumnTypeLength(index int) (int64, bool) { - fd := r.rows.FieldDescriptions()[index] - - switch fd.DataTypeOID { - case pgtype.TextOID, pgtype.ByteaOID: - return math.MaxInt64, true - case pgtype.VarcharOID, pgtype.BPCharArrayOID: - return int64(fd.TypeModifier - varHeaderSize), true - default: - return 0, false - } -} - -// ColumnTypePrecisionScale should return the precision and scale for decimal -// types. If not applicable, ok should be false. -func (r *Rows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) { - fd := r.rows.FieldDescriptions()[index] - - switch fd.DataTypeOID { - case pgtype.NumericOID: - mod := fd.TypeModifier - varHeaderSize - precision = int64((mod >> 16) & 0xffff) - scale = int64(mod & 0xffff) - return precision, scale, true - default: - return 0, 0, false - } -} - -// ColumnTypeScanType returns the value type that can be used to scan types into. -func (r *Rows) ColumnTypeScanType(index int) reflect.Type { - fd := r.rows.FieldDescriptions()[index] - - switch fd.DataTypeOID { - case pgtype.Float8OID: - return reflect.TypeOf(float64(0)) - case pgtype.Float4OID: - return reflect.TypeOf(float32(0)) - case pgtype.Int8OID: - return reflect.TypeOf(int64(0)) - case pgtype.Int4OID: - return reflect.TypeOf(int32(0)) - case pgtype.Int2OID: - return reflect.TypeOf(int16(0)) - case pgtype.BoolOID: - return reflect.TypeOf(false) - case pgtype.NumericOID: - return reflect.TypeOf(float64(0)) - case pgtype.DateOID, pgtype.TimestampOID, pgtype.TimestamptzOID: - return reflect.TypeOf(time.Time{}) - case pgtype.ByteaOID: - return reflect.TypeOf([]byte(nil)) - default: - return reflect.TypeOf("") - } -} - -func (r *Rows) Close() error { - r.rows.Close() - return r.rows.Err() -} - -func (r *Rows) Next(dest []driver.Value) error { - m := r.conn.conn.TypeMap() - fieldDescriptions := r.rows.FieldDescriptions() - - if r.valueFuncs == nil { - r.valueFuncs = make([]rowValueFunc, len(fieldDescriptions)) - - for i, fd := range fieldDescriptions { - dataTypeOID := fd.DataTypeOID - format := fd.Format - - switch fd.DataTypeOID { - case pgtype.BoolOID: - var d bool - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - return d, err - } - case pgtype.ByteaOID: - var d []byte - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - return d, err - } - case pgtype.CIDOID, pgtype.OIDOID, pgtype.XIDOID: - var d pgtype.Uint32 - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - if err != nil { - return nil, err - } - return d.Value() - } - case pgtype.DateOID: - var d pgtype.Date - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - if err != nil { - return nil, err - } - return d.Value() - } - case pgtype.Float4OID: - var d float32 - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - return float64(d), err - } - case pgtype.Float8OID: - var d float64 - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - return d, err - } - case pgtype.Int2OID: - var d int16 - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - return int64(d), err - } - case pgtype.Int4OID: - var d int32 - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - return int64(d), err - } - case pgtype.Int8OID: - var d int64 - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - return d, err - } - case pgtype.JSONOID, pgtype.JSONBOID: - var d []byte - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - if err != nil { - return nil, err - } - return d, nil - } - case pgtype.TimestampOID: - var d pgtype.Timestamp - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - if err != nil { - return nil, err - } - return d.Value() - } - case pgtype.TimestamptzOID: - var d pgtype.Timestamptz - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - if err != nil { - return nil, err - } - return d.Value() - } - case pgtype.XMLOID: - var d []byte - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - if err != nil { - return nil, err - } - return d, nil - } - default: - var d string - scanPlan := m.PlanScan(dataTypeOID, format, &d) - r.valueFuncs[i] = func(src []byte) (driver.Value, error) { - err := scanPlan.Scan(src, &d) - return d, err - } - } - } - } - - var more bool - if r.skipNext { - more = r.skipNextMore - r.skipNext = false - } else { - more = r.rows.Next() - } - - if !more { - if r.rows.Err() == nil { - return io.EOF - } else { - return r.rows.Err() - } - } - - for i, rv := range r.rows.RawValues() { - if rv != nil { - var err error - dest[i], err = r.valueFuncs[i](rv) - if err != nil { - return fmt.Errorf("convert field %d failed: %w", i, err) - } - } else { - dest[i] = nil - } - } - - return nil -} - -func valueToInterface(argsV []driver.Value) []any { - args := make([]any, 0, len(argsV)) - for _, v := range argsV { - if v != nil { - args = append(args, v.(any)) - } else { - args = append(args, nil) - } - } - return args -} - -func namedValueToInterface(argsV []driver.NamedValue) []any { - args := make([]any, 0, len(argsV)) - for _, v := range argsV { - if v.Value != nil { - args = append(args, v.Value.(any)) - } else { - args = append(args, nil) - } - } - return args -} - -type wrapTx struct { - ctx context.Context - tx pgx.Tx -} - -func (wtx wrapTx) Commit() error { return wtx.tx.Commit(wtx.ctx) } - -func (wtx wrapTx) Rollback() error { return wtx.tx.Rollback(wtx.ctx) } |