| | |
| | |
| | |
| |
|
| | |
| |
|
| | package sql |
| |
|
| | import ( |
| | "bytes" |
| | "database/sql/driver" |
| | "errors" |
| | "fmt" |
| | "reflect" |
| | "strconv" |
| | "time" |
| | "unicode" |
| | "unicode/utf8" |
| | _ "unsafe" |
| | ) |
| |
|
| | var errNilPtr = errors.New("destination pointer is nil") |
| |
|
| | func describeNamedValue(nv *driver.NamedValue) string { |
| | if len(nv.Name) == 0 { |
| | return fmt.Sprintf("$%d", nv.Ordinal) |
| | } |
| | return fmt.Sprintf("with name %q", nv.Name) |
| | } |
| |
|
| | func validateNamedValueName(name string) error { |
| | if len(name) == 0 { |
| | return nil |
| | } |
| | r, _ := utf8.DecodeRuneInString(name) |
| | if unicode.IsLetter(r) { |
| | return nil |
| | } |
| | return fmt.Errorf("name %q does not begin with a letter", name) |
| | } |
| |
|
| | |
| | |
| | |
| | type ccChecker struct { |
| | cci driver.ColumnConverter |
| | want int |
| | } |
| |
|
| | func (c ccChecker) CheckNamedValue(nv *driver.NamedValue) error { |
| | if c.cci == nil { |
| | return driver.ErrSkip |
| | } |
| | |
| | |
| | |
| | index := nv.Ordinal - 1 |
| | if c.want >= 0 && c.want <= index { |
| | return nil |
| | } |
| |
|
| | |
| | |
| | |
| | if vr, ok := nv.Value.(driver.Valuer); ok { |
| | sv, err := callValuerValue(vr) |
| | if err != nil { |
| | return err |
| | } |
| | if !driver.IsValue(sv) { |
| | return fmt.Errorf("non-subset type %T returned from Value", sv) |
| | } |
| | nv.Value = sv |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | var err error |
| | arg := nv.Value |
| | nv.Value, err = c.cci.ColumnConverter(index).ConvertValue(arg) |
| | if err != nil { |
| | return err |
| | } |
| | if !driver.IsValue(nv.Value) { |
| | return fmt.Errorf("driver ColumnConverter error converted %T to unsupported type %T", arg, nv.Value) |
| | } |
| | return nil |
| | } |
| |
|
| | |
| | |
| | |
| | func defaultCheckNamedValue(nv *driver.NamedValue) (err error) { |
| | nv.Value, err = driver.DefaultParameterConverter.ConvertValue(nv.Value) |
| | return err |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func driverArgsConnLocked(ci driver.Conn, ds *driverStmt, args []any) ([]driver.NamedValue, error) { |
| | nvargs := make([]driver.NamedValue, len(args)) |
| |
|
| | |
| | |
| | |
| | want := -1 |
| |
|
| | var si driver.Stmt |
| | var cc ccChecker |
| | if ds != nil { |
| | si = ds.si |
| | want = ds.si.NumInput() |
| | cc.want = want |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | nvc, ok := si.(driver.NamedValueChecker) |
| | if !ok { |
| | nvc, _ = ci.(driver.NamedValueChecker) |
| | } |
| | cci, ok := si.(driver.ColumnConverter) |
| | if ok { |
| | cc.cci = cci |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | var err error |
| | var n int |
| | for _, arg := range args { |
| | nv := &nvargs[n] |
| | if np, ok := arg.(NamedArg); ok { |
| | if err = validateNamedValueName(np.Name); err != nil { |
| | return nil, err |
| | } |
| | arg = np.Value |
| | nv.Name = np.Name |
| | } |
| | nv.Ordinal = n + 1 |
| | nv.Value = arg |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | checker := defaultCheckNamedValue |
| | nextCC := false |
| | switch { |
| | case nvc != nil: |
| | nextCC = cci != nil |
| | checker = nvc.CheckNamedValue |
| | case cci != nil: |
| | checker = cc.CheckNamedValue |
| | } |
| |
|
| | nextCheck: |
| | err = checker(nv) |
| | switch err { |
| | case nil: |
| | n++ |
| | continue |
| | case driver.ErrRemoveArgument: |
| | nvargs = nvargs[:len(nvargs)-1] |
| | continue |
| | case driver.ErrSkip: |
| | if nextCC { |
| | nextCC = false |
| | checker = cc.CheckNamedValue |
| | } else { |
| | checker = defaultCheckNamedValue |
| | } |
| | goto nextCheck |
| | default: |
| | return nil, fmt.Errorf("sql: converting argument %s type: %w", describeNamedValue(nv), err) |
| | } |
| | } |
| |
|
| | |
| | |
| | if want != -1 && len(nvargs) != want { |
| | return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(nvargs)) |
| | } |
| |
|
| | return nvargs, nil |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func convertAssign(dest, src any) error { |
| | return convertAssignRows(dest, src, nil) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func convertAssignRows(dest, src any, rows *Rows) error { |
| | |
| | switch s := src.(type) { |
| | case string: |
| | switch d := dest.(type) { |
| | case *string: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | *d = s |
| | return nil |
| | case *[]byte: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | *d = []byte(s) |
| | return nil |
| | case *RawBytes: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | *d = rows.setrawbuf(append(rows.rawbuf(), s...)) |
| | return nil |
| | } |
| | case []byte: |
| | switch d := dest.(type) { |
| | case *string: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | *d = string(s) |
| | return nil |
| | case *any: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | *d = bytes.Clone(s) |
| | return nil |
| | case *[]byte: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | *d = bytes.Clone(s) |
| | return nil |
| | case *RawBytes: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | *d = s |
| | return nil |
| | } |
| | case time.Time: |
| | switch d := dest.(type) { |
| | case *time.Time: |
| | *d = s |
| | return nil |
| | case *string: |
| | *d = s.Format(time.RFC3339Nano) |
| | return nil |
| | case *[]byte: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | *d = s.AppendFormat(make([]byte, 0, len(time.RFC3339Nano)), time.RFC3339Nano) |
| | return nil |
| | case *RawBytes: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | *d = rows.setrawbuf(s.AppendFormat(rows.rawbuf(), time.RFC3339Nano)) |
| | return nil |
| | } |
| | case decimalDecompose: |
| | switch d := dest.(type) { |
| | case decimalCompose: |
| | return d.Compose(s.Decompose(nil)) |
| | } |
| | case nil: |
| | switch d := dest.(type) { |
| | case *any: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | *d = nil |
| | return nil |
| | case *[]byte: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | *d = nil |
| | return nil |
| | case *RawBytes: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | *d = nil |
| | return nil |
| | } |
| | |
| | case driver.Rows: |
| | switch d := dest.(type) { |
| | case *Rows: |
| | if d == nil { |
| | return errNilPtr |
| | } |
| | if rows == nil { |
| | return errors.New("invalid context to convert cursor rows, missing parent *Rows") |
| | } |
| | *d = Rows{ |
| | dc: rows.dc, |
| | releaseConn: func(error) {}, |
| | rowsi: s, |
| | } |
| | |
| | parentCancel := rows.cancel |
| | rows.cancel = func() { |
| | |
| | |
| | d.close(rows.lasterr) |
| | if parentCancel != nil { |
| | parentCancel() |
| | } |
| | } |
| | return nil |
| | } |
| | } |
| |
|
| | var sv reflect.Value |
| |
|
| | switch d := dest.(type) { |
| | case *string: |
| | sv = reflect.ValueOf(src) |
| | switch sv.Kind() { |
| | case reflect.Bool, |
| | reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, |
| | reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, |
| | reflect.Float32, reflect.Float64: |
| | *d = asString(src) |
| | return nil |
| | } |
| | case *[]byte: |
| | sv = reflect.ValueOf(src) |
| | if b, ok := asBytes(nil, sv); ok { |
| | *d = b |
| | return nil |
| | } |
| | case *RawBytes: |
| | sv = reflect.ValueOf(src) |
| | if b, ok := asBytes(rows.rawbuf(), sv); ok { |
| | *d = rows.setrawbuf(b) |
| | return nil |
| | } |
| | case *bool: |
| | bv, err := driver.Bool.ConvertValue(src) |
| | if err == nil { |
| | *d = bv.(bool) |
| | } |
| | return err |
| | case *any: |
| | *d = src |
| | return nil |
| | } |
| |
|
| | if scanner, ok := dest.(Scanner); ok { |
| | return scanner.Scan(src) |
| | } |
| |
|
| | dpv := reflect.ValueOf(dest) |
| | if dpv.Kind() != reflect.Pointer { |
| | return errors.New("destination not a pointer") |
| | } |
| | if dpv.IsNil() { |
| | return errNilPtr |
| | } |
| |
|
| | if !sv.IsValid() { |
| | sv = reflect.ValueOf(src) |
| | } |
| |
|
| | dv := reflect.Indirect(dpv) |
| | if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { |
| | switch b := src.(type) { |
| | case []byte: |
| | dv.Set(reflect.ValueOf(bytes.Clone(b))) |
| | default: |
| | dv.Set(sv) |
| | } |
| | return nil |
| | } |
| |
|
| | if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { |
| | dv.Set(sv.Convert(dv.Type())) |
| | return nil |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | switch dv.Kind() { |
| | case reflect.Pointer: |
| | if src == nil { |
| | dv.SetZero() |
| | return nil |
| | } |
| | dv.Set(reflect.New(dv.Type().Elem())) |
| | return convertAssignRows(dv.Interface(), src, rows) |
| | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
| | if src == nil { |
| | return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) |
| | } |
| | s := asString(src) |
| | i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) |
| | if err != nil { |
| | err = strconvErr(err) |
| | return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) |
| | } |
| | dv.SetInt(i64) |
| | return nil |
| | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
| | if src == nil { |
| | return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) |
| | } |
| | s := asString(src) |
| | u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) |
| | if err != nil { |
| | err = strconvErr(err) |
| | return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) |
| | } |
| | dv.SetUint(u64) |
| | return nil |
| | case reflect.Float32, reflect.Float64: |
| | if src == nil { |
| | return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) |
| | } |
| | s := asString(src) |
| | f64, err := strconv.ParseFloat(s, dv.Type().Bits()) |
| | if err != nil { |
| | err = strconvErr(err) |
| | return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) |
| | } |
| | dv.SetFloat(f64) |
| | return nil |
| | case reflect.String: |
| | if src == nil { |
| | return fmt.Errorf("converting NULL to %s is unsupported", dv.Kind()) |
| | } |
| | switch v := src.(type) { |
| | case string: |
| | dv.SetString(v) |
| | return nil |
| | case []byte: |
| | dv.SetString(string(v)) |
| | return nil |
| | } |
| | } |
| |
|
| | return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) |
| | } |
| |
|
| | func strconvErr(err error) error { |
| | if ne, ok := err.(*strconv.NumError); ok { |
| | return ne.Err |
| | } |
| | return err |
| | } |
| |
|
| | func asString(src any) string { |
| | switch v := src.(type) { |
| | case string: |
| | return v |
| | case []byte: |
| | return string(v) |
| | } |
| | rv := reflect.ValueOf(src) |
| | switch rv.Kind() { |
| | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
| | return strconv.FormatInt(rv.Int(), 10) |
| | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
| | return strconv.FormatUint(rv.Uint(), 10) |
| | case reflect.Float64: |
| | return strconv.FormatFloat(rv.Float(), 'g', -1, 64) |
| | case reflect.Float32: |
| | return strconv.FormatFloat(rv.Float(), 'g', -1, 32) |
| | case reflect.Bool: |
| | return strconv.FormatBool(rv.Bool()) |
| | } |
| | return fmt.Sprintf("%v", src) |
| | } |
| |
|
| | func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) { |
| | switch rv.Kind() { |
| | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
| | return strconv.AppendInt(buf, rv.Int(), 10), true |
| | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
| | return strconv.AppendUint(buf, rv.Uint(), 10), true |
| | case reflect.Float32: |
| | return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true |
| | case reflect.Float64: |
| | return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true |
| | case reflect.Bool: |
| | return strconv.AppendBool(buf, rv.Bool()), true |
| | case reflect.String: |
| | s := rv.String() |
| | return append(buf, s...), true |
| | } |
| | return |
| | } |
| |
|
| | var valuerReflectType = reflect.TypeFor[driver.Valuer]() |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func callValuerValue(vr driver.Valuer) (v driver.Value, err error) { |
| | if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Pointer && |
| | rv.IsNil() && |
| | rv.Type().Elem().Implements(valuerReflectType) { |
| | return nil, nil |
| | } |
| | return vr.Value() |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type decimal interface { |
| | decimalDecompose |
| | decimalCompose |
| | } |
| |
|
| | type decimalDecompose interface { |
| | |
| | |
| | |
| | Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) |
| | } |
| |
|
| | type decimalCompose interface { |
| | |
| | |
| | Compose(form byte, negative bool, coefficient []byte, exponent int32) error |
| | } |
| |
|