Golang+Postgres WHERE clause with a hex value - postgresql

I created a simple sql database with a BYTEA field,
create table testhex (testhex bytea);
insert into testhex (testhex) values ('\x123456');
and then I tried to query it from Go.
package main
import (
"database/sql"
_ "github.com/lib/pq"
)
func main(){
var err error
db, err := sql.Open("postgres", "dbname=testhex sslmode=disable")
if err != nil {
panic(err)
}
var result string
err = db.QueryRow("select testhex from testhex where testhex = $1", `\x123456`).Scan(&result)
if err != nil {
panic(err)
}
}
It doesn't find the row. What am I doing wrong?

When you ran the following query:
insert into testhex (testhex) values ('\x123456');
You inserted the 3 byte sequence [0x12 0x34 0x56] into the table. For the database query you're executing with QueryRow though, you're searching for the 8 character literal string \x123456 so you get no matches in the result.
When you use positional arguments with QueryRow, it is the database adapter's job to convert them to a form the database understands (either by sending them to the database as bound parameters, or by substituting them into the query with appropriate escaping). So by passing an already escaped value you will run into this sort of problem.
Instead, try passing []byte{0x12, 0x34, 0x56} as the positional argument, which should match what is in the database.

Related

golang postgresql: Get query results as comma separated values (csv format)

I'm trying to get results from select query in a comma separated format (don't want results in a file). Following code works fine if I use stmt := fmt.Sprintf("SELECT * FROM table") but below code fails to reproduce any results because rows.Next() is empty. How to resolve this issue?
func (db *Dbq) Getresults() []interface{} {
stmt := fmt.Sprintf("COPY (select * from table) TO STDOUT WITH CSV")
var results []interface{}
rows, err := db.conn.Query(db.context, stmt)
for rows.Next() {
values, err := rows.Values()
if err != nil {
log.Fatal(err)
}
results = append(results, values)
}
rows.Close()
return results
}
I ran code with two different queries and debugged where it failed.

database/sql Exec() function fail with concatenating string

A peculiar error occurred today when was manipulating data in Postgres using database/sql and driver github.com/lib/pq. I have the following SQL schema created in Postgres:
CREATE TABLE IF NOT EXISTS bench_bytea (
id INT PRIMARY KEY,
name VARCHAR,
data BYTEA
);
A very basic table containing a data blob of type BYTEA.
I then tried to execute simple INSERT statement using the Exec() function provided by database/sql. Here it is:
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
panic(err)
}
defer db.Close()
stmt := `INSERT INTO bench_bytea (id, name, data) VALUES ($1, $2, $3) ON CONFLICT (id) DO NOTHING`
data := `{"title": "Sleeping Beauties", "genres": ["Fiction", "Thriller", "Horror"], "published": false}`
i := 0
_, err = db.Exec(stmt, i, "testing "+string(i), []byte(data))
if err != nil {
panic(err)
}
The key highlight happens on the db.Exec() line where I execute a SQL INSERT statement (in practicality i is an index of an array where I stored different testing data. I didn't want to include the other pieces of data here since it's really long and irrelevant). The error I received is:
pq: invalid byte sequence for encoding "UTF8": 0x00
Now if I change "testing "+string(i) into "testing", the error is gone. That is, if I didn't insert a concatenating strings into the name column, there's no error. What is going on here?
You can't convert an integer to a string like that. The result of string(0) is "\x00", aka a null byte, instead of "0" which is probably you want. You should use strconv.Itoa for the conversion instead.

Convert client UUID to SQL UUID

I'm using go and the package uuid to generate a uuid of type [16]byte. However when I try to insert that uuid into my postgres column of type uuid I get the error converting argument $1 type: unsupported type [16]uint8, a array. So apparently I should convert the uuid on the client before I insert it into the db. How should I do that? What type should I convert it to?
In short: What go data type will work with uuid in postgres?
Thanks to the link from #sberry, I found success. Here are snippets of the code for your benefit (with a PostgreSQL 9.5 database):
import (
"database/sql"
"net/http"
"github.com/google/uuid"
)
type Thing struct {
ID uuid.UUID `json:"-" sql:",type:uuid"`
Name string `json:"name"`
}
// For a database table created as such:
// CREATE TABLE things (
// id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
// name TEXT DEFAULT ''::text
// )
func selectThingssSQL() ([]Thing, error) {
things := make([]Thing, 0)
rows, err := db.Query("SELECT id, name FROM things")
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
t := &Thing{}
if err := rows.Scan(&t.ID, &t.Name); err != nil {
return nil, err
}
things = append(things, *t)
}
return things, nil
}

Golang how can I make sql row a string

I am using Golang and Postgres, Postgres has an advance feature where it can return your queries in Json format. What I want to do is get that Json query results and return it but I am having trouble since it has to be a String in order to return it. This is my code
package main
import(
"fmt"
"database/sql"
_ "github.com/lib/pq"
"log"
)
func HelloServer(w http.ResponseWriter, req *http.Request) {
db, err := sql.Open("postgres", "user=postgres password=password dbname=name sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer db.Close()
rows, err := db.Query("select To_Json(t) (SELECT * from cars)t")
io.WriteString(w, "hello, world!\n")
}
func main() {
http.HandleFunc("/hello", HelloServer)
log.Fatal(http.ListenAndServe(":12345", nil))
}
The Rows element returns a Json array how can I turn that Rows element into a String ? For C# and Java I would just append the .ToString() method to it and it would make it a string . As you can see from the code above the io.WriteString takes a String as a second parameter so I want to make the Rows variable a String after it has the Json returned so that I can display it in the browser by passing it to the method. I want to replace the Hello World with the String Rows.
Rows is a sql.Rows type. In order to use the data returned by your database query you will have to iterated over the "rows".
An example from the docs
age := 27
rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
log.Fatal(err)
}
fmt.Printf("%s is %d\n", name, age)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
You should instead use QueryRow because you are expecting the database to return one result. In either case once you have used "Scan" to put the data into your own variable then you can either parse the JSON or print it out.

How do I parametarize an operator?

I have the following sql statement:
SELECT pk, up FROM mytable WHERE 2 > 1 LIMIT 10
This is just for simplicity, obviously. I am able to parameterize any of the integers:
SELECT pk, up FROM mytable WHERE 2 > $1 LIMIT 10
BUT, when I try to parameterize the operator, eg:
SELECT pk, up FROM mytable WHERE 2 $1 1 LIMIT 10
I get:
pq: syntax error at or near "$1"
Full Code:
package main
import (
"database/sql"
_ "github.com/lib/pq"
"log"
)
func main() {
log.SetFlags(log.Lshortfile)
Db, err := sql.Open("postgres", "user=yoitsmeletmein password=supersecretyo host=what.a.host dbname=mydb sslmode=require")
if err != nil {
log.Fatal("Cannot connect to db: ", err)
}
q := `SELECT pk FROM mytable WHERE 2 $1 1 LIMIT 10`
params := []interface{}{">"}
rows, err := Db.Query(q, params...)
if err != nil {
log.Println(err)
} else {
defer rows.Close()
for rows.Next() {
var pk int64
if err := rows.Scan(&pk); err != nil {
log.Fatal(err)
}
log.Println(pk)
}
}
}
Prepared statements allow to parametrize values, nothing else. It wouldn't make sense to parametrize operators to begin with, a statement cannot be prepared without knowing involved operators. And it would be potentially dangerous, opening vectors for SQL injection.
To switch operators, you'll have to concatenate a new query string in your client or use dynamic SQL with a server-side procedural language, the default being plpgsql.