How to update multiple rows using sqlx? - go

I'd like to update multiple rows in a single query:
//threadIDs is a variable length slice of integers like [3 5 6]
query := "UPDATE message SET recipient_deleted=? WHERE recipient_id=? AND thread_id IN ?"
_, err := database.SQL.Exec( query, 1, userID, threadIDs)
if err != nil {
log.Fatal(err)
}
But I get this runtime error:
sql: converting argument $3 type: unsupported type []int, a slice of int
How can I fix this?

You can use sqlx.In which returns a new query and a new args slice that you then use instead of your original values, like so:
query := "UPDATE message SET recipient_deleted=? WHERE recipient_id=? AND thread_id IN (?)"
qry, args, err := sqlx.In(query, 1, userID, threadIDs)
if err != nil {
panic(err)
}
if _, err := database.SQL.Exec(qry, args...); err != nil {
panic(err)
}

Related

MonetDB Insert Statement Returning id support in Golang

I am trying to run this insert query statement using golang which should return an id
INSERT INTO users (u_email,u_phone,u_password_hash) VALUES (?,?,?) RETURNING u_user_id;
it seems there is no support for that in MonetDB.
Well i tried to get the id by unique email when the insert is done without the "RETURNING u_user_id" part as below
func GetByEmail(db *sql.DB) {
userid := `SELECT u_user_id FROM users WHERE u_email = ?;`
var id UserResponse
email := `baicmr#email.com`
stmt, err := db.Prepare(userid)
if err != nil {
log.Panic(err)
}
defer stmt.Close()
result := stmt.QueryRow(email)
if getErr := result.Scan(&id.ID); getErr != nil {
log.Panic(getErr)
}
fmt.Printf("id.ID: %v\n", id.ID)
}
the result.Scan() line panics
panic: runtime error: index out of range [0] with length 0
What am i doing which is wrong
Can you please open a issue/feature request over at: https://github.com/MonetDB/MonetDB-Go ? This looks like a bug.

Golang godror - execute a PL/SQL Cursor

I'm trying to retrieve cursor result of a PL/SQL function in golang with godror.
https://github.com/godror/godror
Using cursors returned by stored procedures
Use ExecContext and an interface{} or a database/sql/driver.Rows as the sql.Out destination, then either use the driver.Rows interface, or transform it into a regular *sql.Rows with godror.WrapRows, or (since Go 1.12) just Scan into *sql.Rows.
db, err := sql.Open("godror", "api/user#localhost/DEV")
if err != nil {
fmt.Println(err)
panic(err)
}
defer db.Close()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
const query = `
DECLARE
BEGIN
:cursor := pkg_api.my_func(pstr_logn_nm => 'my_name');
END;
`
stmt, err := db.PrepareContext(ctx, query)
if err != nil {
fmt.Println(err)
panic(err)
}
var rows driver.Rows
_, err = stmt.ExecContext(ctx, sql.Out{Dest: &rows})
if err != nil {
fmt.Println(err)
}
var r []driver.Value
err = rows.Next(r)
if err != nil {
fmt.Println(err) // column count mismatch: we have 10 columns, but given 0 destination
}
defer rows.Close()
fmt.Println(rows.Columns()) // [COL_1 COL_2 COL_3 COL_4 COL_5 COL_6 COL_7 COL_8 COL_9 COL_10]
I have an error: column count mismatch: we have 10 columns, but given 0 destination
To my point of view it's because I have to define an interface with some columns.
If I try to change driver.Rows by sql.Rows I have this error:
arg: unknown type sql.Rows
If I try to create an interface I:
type I interface {
NM() string
}
var r []I
err = rows.Next(r)
I have this error: cannot use r (type []I) as type []driver.Value in argument to rows.Next
I'm also new in Golang, if someone has an idea :)
Thanks a lot!
This solved my problem!
r := make([]driver.Value, len(rows.Columns()))
err = rows.Next(r)
if err != nil {
fmt.Println(err) // column count mismatch: we have 10 columns, but given 0 destination
}
defer rows.Close()
https://github.com/godror/godror/issues/62

How to query and handle a UUID created with go.uuid and inserted into PostgreSQL 11?

I inserted in PostgreSQL table an UUID created with go.uuid :
import (
"github.com/satori/go.uuid"
)
func main() {
usid := uuid.Must(uuid.NewV4())
fmt.Println("usid := uuid.Must(uuid.NewV4")
fmt.Println(usid.String())
res, err := stmt.Exec(cn, csn, ccn, id)
if err != nil || res == nil {
log.Fatal(err)
}
}
sStmt := "insert into basicuserinfo (cn, csn, ccn, appUserAccountID )
values ($1, $2, $3, $4)"
stmt, err := db.Prepare(sStmt)
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
fmt.Println("# Inserting values")
And actually a row is inserted in the postgreSQL db:
cn | csn | ccn | id
| 2412fcd3-8712-4a0f-830a-d77bd4cf2195
In order to query with golang variables I tried first, to use a prepared statement.
First, using db.PrepareContext :
sel := "SELECT appUserAccountID FROM basicuserinfo WHERE cn = $1 AND csn
= $2 AND ccn = $3"
stmt, err = db.PrepareContext(ctx,sel)
if err != nil {
log.Fatal(err)
}
var utenteID string
err = stmt.QueryRowContext(ctx,cn, csn, ccn).Scan(&utenteID)
log.Printf("ID= %s\n", utenteID)
fmt.Println("aaaaaaaaa") // Just to check that the this line gets executed
Whose execution remains "idle", in stand-by, without ending and producing any output:
marco#pc01:~/go/marcoGolang/goPostgres$ go run pqExample00.go
# Inserting values
Then I tried in this way, with db.Prepare():
stmt, err = db.Prepare(sel)
if err != nil {
log.Fatal(err)
}
res, err = stmt.Exec(cnv, csnv, ccnv)
In this second case the execution seems ending successfully, but I do not know how to convert the sql.Result into a correct form which can be handled, for example simply displayed with fmt.Println() or getting other handlings.
So... how to correctly query and handle a UUID created with go.uuid and inserted into PostgreSQL 11?
Looking forward to your kind help.
Marco
Unless you have a reason for using PrepareContext, you could just do this?
db, err := sql.Open("postgres", connectionString)
sel := "SELECT appUserAccountID FROM basicuserinfo WHERE cn = $1 AND csn = $2 AND ccn = $3"
var idn string
err = db.QueryRow(sel, cn, csn, ccn).Scan(&idn)
if err != nil {
log.Fatal(err)
}
fmt.Printf("idn: %v\n", idn)

Query for an integer array from PostreSQL always returns []uint8

Take a simple PostreSQL db with an integer array:
CREATE TABLE foo (
id serial PRIMARY KEY,
bar integer[]
);
INSERT INTO foo VALUES(DEFAULT, '{1234567, 20, 30, 40}');
Using pq, these values are for some reason being retrieved as an array of []uint8.
The documentation says that integer types are returned as int64. Does this not apply to arrays as well?
db, err := sql.Open("postgres", "user=a_user password=your_pwd dbname=blah")
if err != nil {
fmt.Println(err)
}
var ret []int
err = db.QueryRow("SELECT bar FROM foo WHERE id=$1", 1).Scan(&ret)
if err != nil {
fmt.Println(err)
}
fmt.Println(ret)
Output:
sql: Scan error on column index 0: unsupported Scan, storing driver.Value type []uint8 into type *[]int64
[]
You cannot use a slice of int as a driver.Value. The arguments to Scan must be of one of the supported types, or implement the sql.Scanner interface.
The reason you're seeing []uint8 in the error message is that the raw value returned from the database is a []byte slice, for which []uint8 is a synonym.
To interpret that []byte slice appropriately as a custom PostgreSQL array type, you should use the appropriate array types defined in the pq package, such as the Int64Array.
Try something like this:
var ret pq.Int64Array
err = db.QueryRow("SELECT bar FROM foo WHERE id=$1", 1).Scan(&ret)
if err != nil {
fmt.Println(err)
}
fmt.Println(ret)
The problem will be more severe if you use fetching multiple rows.
The above code works for a single row, to fetch multiple rows use like this
`rows, err := db.QueryContext(ctx, stmt, courseCode)
if err != nil {
return nil, err
}
defer rows.Close()
var feedbacks []*Feedback1
for rows.Next() {
var feedback Feedback1
var ret pq.Int64Array
var ret1 pq.Int64Array
err := rows.Scan(
&feedback.ID,
&ret,
&ret1,
)
if err != nil {
return nil, err
}
//for loop to convert int64 to int
for i:=0;i<len(ret);i++{
feedback.UnitFeedback = append(feedback.UnitFeedback,int(ret[i]))}
for i:=0;i<len(ret1);i++{
feedback.GeneralFeedback = append(feedback.GeneralFeedback,int(ret1[i]))}
feedbacks = append(feedbacks, &feedback)
}`

Go Using db.Query to return more than one column

In the Go SQL docs they give an example here of a query that only returns 1 column (poor example in my opinion, at least return 2...)
age := 27
rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
if err != nil {
log.Fatal(err)
}
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)
}
The docs state here that
Scan copies the columns in the current row into the values pointed at by dest.
How does this work with a struct, lets say I have a struct
type User struct{
Name string
Age int
}
and I modify my query to SELECT name, age from users where age=?
How do I unpack *Rows into my struct? I did find this example, but it didn't deal with structs. I will be following Active Record pattern conventions so my structs will map to my database via snake case conversion.
Looking at the source, it seems the copy is done with ... syntax on destination pointers:
func (rs *Rows) Scan(dest ...interface{}) error
So in your example, you can do for instance:
for rows.Next() {
u := User{} // An empty user
...
if err := rows.Scan(&u.Name, &u.Age); err != nil {
...
}
}
As long as you pass the exact number of pointers, this should work, whether they are from a struct or not.

Resources