func (p *PostgresFilesystem) Open(name string) (File, error) {
	tx, err := p.db.Begin()
	if err != nil {
		return nil, err
	}

	var f pgFile
	err = tx.QueryRow("SELECT file_id, size, type, digest, created_at FROM files WHERE name = $1",
		name).Scan(&f.id, &f.size, &f.typ, &f.etag, &f.mtime)
	if err != nil {
		tx.Rollback()
		if err == sql.ErrNoRows {
			err = ErrNotFound
		}
		return nil, err
	}

	lo, err := pq.NewLargeObjects(tx)
	if err != nil {
		tx.Rollback()
		return nil, err
	}
	f.LargeObject, err = lo.Open(f.id, pq.LargeObjectModeRead)
	if err != nil {
		tx.Rollback()
		return nil, err
	}
	f.tx = tx

	return &f, nil
}
func (p *PostgresFilesystem) Put(name string, r io.Reader, typ string) error {
	tx, err := p.db.Begin()
	if err != nil {
		return err
	}

	var id oid.Oid
create:
	err = tx.QueryRow("INSERT INTO files (name, type) VALUES ($1, $2) RETURNING file_id", name, typ).Scan(&id)
	if e, ok := err.(*pq.Error); ok && e.Code.Name() == "unique_violation" {
		tx.Rollback()
		tx, err = p.db.Begin()
		if err != nil {
			return err
		}

		// file exists, delete it first
		_, err = tx.Exec("DELETE FROM files WHERE name = $1", name)
		if err != nil {
			tx.Rollback()
			return err
		}
		goto create
	}
	if err != nil {
		tx.Rollback()
		return err
	}

	lo, err := pq.NewLargeObjects(tx)
	if err != nil {
		tx.Rollback()
		return err
	}
	obj, err := lo.Open(id, pq.LargeObjectModeWrite)
	if err != nil {
		tx.Rollback()
		return err
	}

	h := sha512.New()
	size, err := io.Copy(obj, io.TeeReader(r, h))
	if err != nil {
		tx.Rollback()
		return err
	}

	digest := hex.EncodeToString(h.Sum(nil))
	_, err = tx.Exec("UPDATE files SET size = $2, digest = $3 WHERE file_id = $1", id, size, digest)
	if err != nil {
		tx.Rollback()
		return err
	}

	return tx.Commit()
}