Postgres SELECT in Go returns all columns as string (using pq and database/sql)
Asked Answered
B

2

6

I'm doing a select in Go using the database/sql package and the pq Postgres driver:

rows, err := db.Query("SELECT (name, age) FROM people WHERE id = 1")

I tried retrieving the values in the normal way:

rows.Next()
name := ""
age := 0
err = rows.Scan(&name, &age)

but I got the error:

sql: expected 1 destination arguments in Scan, not 2

The documentation for sql.(*Rows).Scan says that you can pass a byte slice pointer and it will be filled with the raw results. So I did this:

b := make([]byte, 1024*1024)
rows.Scan(&b)
fmt.Println(string(b))

which succeeded, printing:

(John,18)

So I looked at the source code for sql.(*Rows).Scan, and it turns out that the error is returned if the number of arguments doesn't match the number of results returned by the database driver (which makes sense). So, for some reason, the pq driver seems to be returning the result set as a single value. Why would this be?

Blithesome answered 6/1, 2014 at 22:42 Comment(6)
Remove the parentheses around the columns in the select list. SELECT (name, age) returns a single record (an anonymous composite type), but SELECT name, age will return two columnsNearsighted
Is this a Postgres-only feature?Blithesome
@joshlf13 You'd probably need to look into the standard to find out, and it's "fun" reading. I think the standard supports it for things like UPDATE ... SET (a, b) = (x, y), and PostgreSQL has just generalized that by treating (a,b) as shorthand for ROW(a,b).Hockey
@a_horse_with_no_name : but what about if the query is calling a function which returns a query, such as RETURN QUERY SELECT arg1, arg2 removing parentheses doesn't work for functionsBystreet
@Joe: no idea what you mean with that. If you then run select * from function() there is no need to remove any parenthesesNearsighted
@a_horse_with_no_name sorry, I was confused, I thought maybe the return type of the function can produce this bug too (Query return). The problem is resolved as u mentioned in comments, query was sth like select from function ! thx for ur responseBystreet
B
6

Thanks to a_horse_with_no_name for the right answer! I'm posting it here for ... posterity?

In Postgres, doing SELECT (a, b) with parentheses returns a single record, which is an anonymous composite type. Removing the parentheses will return the columns individually: Select a, b.

Blithesome answered 6/1, 2014 at 23:44 Comment(0)
R
2

When using a function with out parameters which only ever returns one row I was running into the same issue. The following resolved it for me:

var foo, bar string
err := db.QueryRow("select * from my_function()").Scan(&foo, &bar)

The function was of this form:

create or replace function my_function(
  out first_out varchar,
  out second_out json
) as $$
  -- etc.
$$ language plpgsql;
Ronna answered 4/2, 2015 at 9:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.