// Scan parses the values of the current result row (set using Result.Next) // into the given arguments. func (r *Result) Scan(args ...interface{}) os.Error { if len(args) != r.ncols { return os.NewError(fmt.Sprintf("incorrect argument count for Result.Scan: have %d want %d", len(args), r.ncols)) } for i, v := range args { if int(C.PQgetisnull(r.res, C.int(r.currRow), C.int(i))) == 1 { continue } val := C.GoString(C.PQgetvalue(r.res, C.int(r.currRow), C.int(i))) switch v := v.(type) { case *[]byte: if !strings.HasPrefix(val, "\\x") { return argErr(i, "[]byte", "invalid byte string format") } buf, err := hex.DecodeString(val[2:]) if err != nil { return argErr(i, "[]byte", err.String()) } *v = buf case *string: *v = val case *bool: *v = val == "t" case *int: x, err := strconv.Atoi(val) if err != nil { return argErr(i, "int", err.String()) } *v = x case *int64: x, err := strconv.Atoi64(val) if err != nil { return argErr(i, "int64", err.String()) } *v = x case *float32: x, err := strconv.Atof32(val) if err != nil { return argErr(i, "float32", err.String()) } *v = x case *float64: x, err := strconv.Atof64(val) if err != nil { return argErr(i, "float64", err.String()) } *v = x case *time.Time: x, _, err := ParseTimestamp(val) if err != nil { return argErr(i, "time.Time", err.String()) } *v = *x default: return os.NewError("unsupported type in Scan: " + reflect.TypeOf(v).String()) } } return nil }
func (r *libpqRows) Next(dest []driver.Value) error { if r.currRow >= r.nrows { return io.EOF } currRow := C.int(r.currRow) r.currRow++ for i := 0; i < len(dest); i++ { ci := C.int(i) // check for NULL if int(C.PQgetisnull(r.res, currRow, ci)) == 1 { dest[i] = nil continue } var err error val := C.GoString(C.PQgetvalue(r.res, currRow, ci)) switch vtype := int(C.PQftype(r.res, ci)); vtype { case r.s.c.oids.Bytea: if !strings.HasPrefix(val, `\x`) { return errors.New("libpq: invalid byte string format") } dest[i], err = hex.DecodeString(val[2:]) if err != nil { return errors.New(fmt.Sprint("libpq: could not decode hex string: %s", err)) } case r.s.c.oids.Date: dest[i], err = time.Parse("2006-01-02", val) if err != nil { return errors.New(fmt.Sprint("libpq: could not parse DATE %s: %s", val, err)) } case r.s.c.oids.Timestamp: dest[i], err = time.Parse("2006-01-02 15:04:05", val) if err != nil { return errors.New(fmt.Sprint("libpq: could not parse TIMESTAMP %s: %s", val, err)) } case r.s.c.oids.TimestampTz: dest[i], err = time.Parse(timeFormat, val) if err != nil { return errors.New(fmt.Sprint("libpq: could not parse TIMESTAMP WITH TIME ZONE %s: %s", val, err)) } case r.s.c.oids.Time: dest[i], err = time.Parse("15:04:05", val) if err != nil { return errors.New(fmt.Sprint("libpq: could not parse TIME %s: %s", val, err)) } case r.s.c.oids.TimeTz: dest[i], err = time.Parse("15:04:05-07", val) if err != nil { return errors.New(fmt.Sprint("libpq: could not parse TIME WITH TIME ZONE %s: %s", val, err)) } default: dest[i] = val } } return nil }
func (d *libpqDriver) getOids(db *C.PGconn, dsn string) (*pqoid, error) { var err error d.Lock() defer d.Unlock() // check cache if oids, ok := d.oids[dsn]; ok { return oids, nil } // not in cache - query the database oids := &pqoid{} names := []struct { kind string dest *int }{ {"'bytea'", &oids.Bytea}, {"'date'", &oids.Date}, {"'timestamp'", &oids.Timestamp}, {"'timestamp with time zone'", &oids.TimestampTz}, {"'time'", &oids.Time}, {"'time with time zone'", &oids.TimeTz}, } // fetch all the OIDs we care about for _, n := range names { ccmd := C.CString("SELECT " + n.kind + "::regtype::oid") defer C.free(unsafe.Pointer(ccmd)) cres := C.PQexec(db, ccmd) defer C.PQclear(cres) if err := resultError(cres); err != nil { return nil, err } sval := C.GoString(C.PQgetvalue(cres, 0, 0)) *n.dest, err = strconv.Atoi(sval) if err != nil { return nil, ErrFetchingOids } } // save in cache for next time d.oids[dsn] = oids return oids, nil }
func (r *driverRows) Next(dest []driver.Value) error { r.currRow++ if r.currRow >= r.nrows { return io.EOF } for i := 0; i < len(dest); i++ { if int(C.PQgetisnull(r.res, C.int(r.currRow), C.int(i))) == 1 { dest[i] = nil continue } val := C.GoString(C.PQgetvalue(r.res, C.int(r.currRow), C.int(i))) switch vtype := uint(C.PQftype(r.res, C.int(i))); vtype { case BOOLOID: if val == "t" { dest[i] = "true" } else { dest[i] = "false" } case BYTEAOID: if !strings.HasPrefix(val, "\\x") { return argErr(i, "[]byte", "invalid byte string format") } buf, err := hex.DecodeString(val[2:]) if err != nil { return argErr(i, "[]byte", err.Error()) } dest[i] = buf case CHAROID, BPCHAROID, VARCHAROID, TEXTOID, INT2OID, INT4OID, INT8OID, OIDOID, XIDOID, FLOAT8OID, FLOAT4OID, DATEOID, TIMEOID, TIMESTAMPOID, TIMESTAMPTZOID, INTERVALOID, TIMETZOID, NUMERICOID: dest[i] = val default: return errors.New(fmt.Sprintf("unsupported type oid: %d", vtype)) } } return nil }
func next(r *PgRows, dest []driver.Value) error { if r.cur >= int(C.PQntuples(r.result)) { return io.EOF } // TODO: cache oids // TODO: extendibility for i := 0; i < len(dest); i++ { if 0 == int(C.PQgetisnull(r.result, C.int(r.cur), C.int(i))) { oid := int(C.PQftype(r.result, C.int(i))) data := C.PQgetvalue(r.result, C.int(r.cur), C.int(i)) length := C.PQgetlength(r.result, C.int(r.cur), C.int(i)) var err error dest[i], err = typecast(oid, data, length, r) if err != nil { return err } } else { dest[i] = nil } } r.cur++ return nil }