Search code examples
sqlgosqlx

SQL insert slice of interface


I'm writing a function that add one row to an SQLite database.

func ManageDB(db *sqlx.DB, query string, args ...interface{}) (int64, error) {

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

    tx, err := db.Begin()
    if err != nil {
        return -1, err
    }
    _, err = tx.Stmt(stmt).Exec(args...)
    if err != nil {
        log.Errorf("error inserting row '%s' %v", query, err)
        log.Debugln("Doing rollback on Insert")
        tx.Rollback()
    } else {
        tx.Commit()
    }

  return res.LastInsertId()
}

and I call it with with that


b := "INSERT INTO MYTABLE (name1, name2, name3, name4) VALUES($1, $2, $3, $4)"

c := []interface{}{
      "string1",
      "string2",
      0,          // int64
      "string4", //string4 
    }

idt, err := models.ManageDB(
      db,  //db initialized 
      b,
      c,
    ) 

.......

When I test that function it works like it should, and add items without problem.

When I run it on the main code, it reports this error:

sql: converting argument $1 type: unsupported type []interface {}, a slice of interface

I don't understand what is wrong.


Solution

  • In the second snippet, you are not spreading c over the arguments, you are simply passing c. Therefore in ManageDB, args is equal to:

    []interface{}{
        []interface{}{
            "string1",
            "string2",
            0,
            "string4",
        }
    }
    

    And so sqlx thinks you want $1 to be that whole array.

    Fix would be to call ManageDB like so:

    models.ManageDB(db, b, c...)