Пример #1
0
// 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
}
Пример #2
0
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
}
Пример #3
0
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
}
Пример #4
0
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
}
Пример #5
0
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
}