Replies: 2 comments
-
There isn't a way to send raw bytes to But perhaps it would be simpler to change your query path. If you used the pgx interface and called Values() you would get appropriately typed values that should be sendable via |
Beta Was this translation helpful? Give feedback.
-
Thank you @jackc for the reply. After much more headbanging and subtle bugs I am trying a new approach which I "think" might be better, but I could really use your assistance for part of it. Again the goal is to be "generic" as I don't want my application to be tied to the underlying table structure (its complicated). Basically, I am doing var rows [][]any
for rowResult.Next() {
rowValues, err := rowResult.Values()
if err != nil {
return nil, err
}
rows = append(rows, rowValues)
} Later on as part of my application I need to write out a .csv file of these rows such that it can later be ingested via postgres's COPY FROM via psql. That is, it should be possible to run However, to write the csv it needs to write the fields correctly for COPY FROM to work correctly. For example, for TIMESTAMP it should be The issue is I am having trouble finding a generic way to correctly write out the rows which have type [][]any such that they get printed correctly as explained in the previous paragraph. Naively, my first approach is the following: for _, row := range q.Rows {
var line []string
for _, field := range row {
fieldAsString := fmt.Sprint(field)
line = append(line, fieldAsString)
}
err := csvWriter.Write(line)
if err != nil {
return "", fmt.Errorf("writing csv line %q: %w", line, err)
}
} Maybe I can save Ugh! It looks like pgxConfig, err := pgxpool.ParseConfig(myConnectionString)
if err != nil {
return nil, fmt.Errorf("unable to parse config: %v", err)
}
var typeMap *pgtype.Map
pgxConfig.BeforeAcquire = func(ctx context.Context, conn *pgx.Conn) bool {
typeMap = conn.TypeMap() // save typeMap
return true
}
conn, err := pgxpool.NewWithConfig(context.Background(), pgxConfig)
if err != nil {
return nil, err
} The following seems to work I think. err = csvWriter.Write(headers)
if err != nil {
return "", fmt.Errorf("writing csv columns %q: %w", p.FieldDescriptions, err)
}
for _, row := range p.Rows {
var line []string
for i, field := range row {
encodedField, err := p.encodeField(field, p.FieldDescriptions[i])
if err != nil {
return "", err
}
line = append(line, encodedField)
}
err := csvWriter.Write(line)
if err != nil {
return "", fmt.Errorf("writing csv line %q: %w", line, err)
}
}
// .........
func (p PgxResult) encodeField(field any, fieldDescription pgconn.FieldDescription) (string, error) {
encodedField, err := p.TypeMap.Encode(fieldDescription.DataTypeOID, pgtype.TextFormatCode, field, nil)
if err != nil {
return "", err
}
if encodedField == nil {
return "NULL", nil
}
return string(encodedField), nil
} Any ideas? |
Beta Was this translation helpful? Give feedback.
-
Basically, I need a "generic" query since I don't want my application to be tied to the underlying table structure (its complicated). However scanning into an interface or rawbytes fails when running CopyFrom() due to not being able to encode timestamp data type. Any ideas or suggestions @jackc ?
I do some business logic on the rows, and later on in my code we want to do a CopyFrom into another database such as:
which failed with:
Also tried something like:
which failed with:
Beta Was this translation helpful? Give feedback.
All reactions