8

my golang sqlite insert function. i'm using this package "github.com/mattn/go-sqlite3"

func Insert(args ...string)(err error){
  db, err:=sql.Open("sqlite3","sqlite.db")
  if err !=nil {
    return
  }
  q, err := db.Prepare(args[0])
  if err !=nil{
    return
  }
  _,err = q.Exec(args[1:]...)
  return
 }
main (){
  err := Insert("INSERT INTO table(first,last) VALUES(?,?)","Nantha","nk")
  if err !=nil{
  fmt.Println(err.Error())
    return
  }
}

i'm getting this error

cannot use args (type []string) as type []interface {} in argument to q.Exec

Ram
  • 506
  • 2
  • 5
  • 15

1 Answers1

8

The error is pretty clear, the function expects type []interface{} but you're passing in a value of type []string. You have to first convert []string to []interface{} before passing it to Exec. And the way to do that is to loop over the strings and add each one to a new slice of interface{}.

https://golang.org/doc/faq#convert_slice_of_interface


As an alternative approach, you can change the Insert argument types.

func Insert(query string, args ...interface{}) (err error) {
    db, err := sql.Open("sqlite3", "sqlite.db")
    if err != nil {
        return err
    }
    q, err := db.Prepare(query)
    if err != nil {
        return err
    }
    _, err = q.Exec(args...)
    return err
}

func main() {
    err := Insert("INSERT INTO table(first,last) VALUES(?,?)", "Nantha", "nk")
    if err !=nil{
        fmt.Println(err.Error())
        return
    }
}

Please note that you're using the database/sql package incorrectly. Many of the objects returned from that package's functions/methods need to be closed to release the underlying resources.

This is true for *sql.DB returned by Open, *sql.Stmt returned by Prepare, *sql.Rows returned by Query, etc.

So your function should look closer to something like this:

func Insert(query string, args ...interface{}) (err error) {
    db, err := sql.Open("sqlite3", "sqlite.db")
    if err != nil {
        return err
    }
    defer db.Close()

    q, err := db.Prepare(query)
    if err != nil {
        return err
    }
    defer q.Close()

    _, err = q.Exec(args...)
    return err
}

Also note that sql.DB is reusable, that means that you don't have to sql.Open a new instance every time you need to talk to the database.

From the docs on Open:

The returned DB is safe for concurrent use by multiple goroutines and maintains its own pool of idle connections. Thus, the Open function should be called just once. It is rarely necessary to close a DB.

If you keep doing it the way you're doing it, openning a new DB every time you call Insert or any other function that needs to talk to the DB, your program will perform worse than if you had a single DB and have your functions reuse that.

mkopriva
  • 35,176
  • 4
  • 57
  • 71
  • v:= []interface{}{"nantha","nk"} -> Insert(q,v) i'm getting unsupported type []interface {}, a slice of interface – Ram Sep 10 '19 at 10:37
  • @Nantha You don't need to do that, `Insert(q, "Nantha", "nk")` will still work, even after you change the `Insert` to `Insert(query string, args ...interface{})` – mkopriva Sep 10 '19 at 10:39
  • @Nantha and if you want to use `v := []interface{}{"nantha","nk"}`, you can do it like this `Insert(q, v...)`. – mkopriva Sep 10 '19 at 10:41
  • it's working :) thank you so much – Ram Sep 10 '19 at 10:51
  • 1
    sorry but this is ridiculous, i need to copy my string array/slice to interface array/slice because I wanted to write generic function that can accept any type? – Verthais Feb 25 '23 at 17:10