How to fetch multiple column from mysql using go lang - mysql

I am trying to fetch multiple columns in a mysql database using the go language. Currently I could modify this script, and it would work perfectly well for just fetching one column, and printing it using the http print function. However, when it fetches two things the script no longer works. I don't have any idea what I need to do to fix it. I know that the sql is fine as I have tested that out in the mysql terminal, and it has given me the expected result that I wanted.
conn, err := sql.Open("mysql", "user:password#tcp(localhost:3306)/database")
statement, err := conn.Prepare("select first,second from table")
rows, err := statement.Query()
for rows.Next() {
var first string
rows.Scan(&first)
var second string
rows.Scan(&second)
fmt.Fprintf(w, "Title of first is :"+first+"The second is"+second)
}
conn.Close()

You are using the wrong variable names but I assume that's just a "typo" in your sample code.
Then the correct syntax is:
var first, second string
rows.Scan(&first, &second)
See this on what Scan(dest ...interface{}) means and how to use it.
You should also handle and not ignore the errors.
Finally, you should use Fprintf as it's intended:
fmt.Fprintf(w, "Title of first is : %s\nThe second is: %s", first, second)

Related

go mysql LAST_INSERT_ID() returns 0

I have this MySQL database where I need to add records with a go program and need to retrieve the id of the last added record, to add the id to another table.
When i run insert INSERT INTO table1 values("test",1); SELECT LAST_INSERT_ID() in MySQL Workbench, it returns the last id, which is auto incremented, with no issues.
If I run my go code however, it always prints 0. The code:
_, err := db_client.DBClient.Query("insert into table1 values(?,?)", name, 1)
var id string
err = db_client.DBClient.QueryRow("SELECT LAST_INSERT_ID()").Scan(&id)
if err != nil {
panic(err.Error())
}
fmt.Println("id: ", id)
I tried this variation to try to narrow down the problem scope further: err = db_client.DBClient.QueryRow("SELECT id from table1 where name=\"pleasejustwork\";").Scan(&id), which works perfectly fine; go returns the actual id.
Why is it not working with the LAST_INSERT_ID()?
I'm a newbie in go so please do not go hard on me if i'm making stupid go mistakes that lead to this error :D
Thank you in advance.
The MySQL protocol returns LAST_INSERT_ID() values in its response to INSERT statements. And, the golang driver exposes that returned value. So, you don't need the extra round trip to get it. These ID values are usually unsigned 64-bit integers.
Try something like this.
res, err := db_client.DBClient.Exec("insert into table1 values(?,?)", name, 1)
if err != nil {
panic (err.Error())
}
id, err := res.LastInsertId()
if err != nil {
panic (err.Error())
}
fmt.Println("id: ", id)
I confess I'm not sure why your code didn't work. Whenever you successfully issue a single-row INSERT statement, the next statement on the same database connection always has access to a useful LAST_INSERT_ID() value. This is true whether or not you use explicit transactions.
But if your INSERT is not successful, you must treat the last insert ID value as unpredictable. (That's a technical term for "garbage", trash, rubbish, basura, etc.)

Using placeholder ? in Go mySql query for anything other than int

I've already setup and pinged my mysql database connection. It is working and I can return rows using both db.Query and by preparing a query first. I can use the placeholder ? to then specify an id. Is it possible to use the ? as a placeholder for a column name? In the example here I am trying to return all rows from column firstName in table persons.
qry, err := db.Prepare("SELECT ? FROM persons")
if err != nil { log.Fatal(err) }
defer qry.Close()
rows, err :=qry.Query("firstName")
if err != nil { log.Fatal(err) }
defer rows.Close()
I get the following error:
Error 1064: You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right
syntax to use near '?' at line 1
You can't use placeholders for identifiers (such as table and column names), placeholders are for values. You can think of identifiers as being similar to variable or function names in Go so being able to use placeholders for identifiers would be akin to having an eval as in various scripting languages.
This reduces you to using fmt.Sprintf and similar string operations for building the SQL when you don't know the identifiers until runtime:
col := "firstName"
sql := fmt.Sprintf("select %s from persons", col)
but this opens you up to SQL injection and quoting problems so you'd want some sort of whitelist:
quotedColumns := map[string]string{
"firstName": "`firstName`",
"lastName": "`lastName`",
...
}
quoted, ok := quotedColumns[columnName]
if !ok {
// Do something with the error here and run away...
}
sql := fmt.Sprintf("select %s from persons", quoted)
Note that I've included the MySQL backtick quoting in the map's values. There's nothing in the standard interface for quoting/escaping an identifier so you have to do it yourself. If you're already writing the whitelist map by hand then you may as well include the quoting by hand too; otherwise you could write your own quoting function for identifiers by reading the MySQL documentation on quoting and doing a couple (hopefully) simple string operations.

building a dynamic query in mysql and golang

How can I build a dynamic query depending on the parameters that I get?
This example is stupid and the syntax is wrong but you will get the idea of what I want.
I guess that I need to add a slice of variables to the end of the query.
I know how to do it in PHP, but not in golang.
db := OpenDB()
defer db.Close()
var filter string
if name != "" {
filter = filter " AND name = ?"
}
if surname != "" {
filter = filter + " AND surname = ?"
}
if address != "" {
filter = filter + " AND address = ?"
}
err = db.Query("SELECT id FROM users WHERE login = ?" +
filter, login)
To answer your question on how to format the string, the simple answer is to use fmt.Sprintf to structure your string. However see further down for a quick note on using fmt.Sprintf for db queries:
Sprintf formats according to a format specifier and returns the resulting string.
Example:
query := fmt.Sprintf("SELECT id FROM users WHERE login='%s'", login)
err = db.Query(query)
// Equivalent to:
rows, err := db.Query("SELECT id FROM users WHERE login=?", login)
Using this for queries, you're safe from injections. That being said, you might be tempted to modify this and use db.Exec for creations/updates/deletions as well. As a general rule of thumb, if you use db.Exec with fmt.Sprintf and do not sanitize your inputs first, you open yourself up to sql injections.
GoPlay with simple example of why fmt.Sprintf with db.Exec is bad:
https://play.golang.org/p/-IWyymAg_Q
You should use db.Query or db.Prepare in an appropriate way to avoid these sorts of attack vectors. You might have to modify the code sample above to come up with a injection-safe snippet, but hopefully I gave you enough to get started.

go - How do i use gorp select for an empty interface

Hi i am using gorp and want to use select query for any table without actually knowing its schema
for that i am using the query
db, err := sql.Open("mysql", "root:1234#tcp(localhost:3306)/information_schema")
checkErr(err, "sql.Open failed")
dbmap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{}}
var data []interface{}
_, err = dbmap.Select(&data, "select * from collations")
checkErr(err, "select query failed")
fmt.Println(data)
}
However this is resulting in an error because i can only pass a struct as first parameter to select
this returns an error
select query failed gorp: select into non-struct slice requires 1 column, got 6
suggest me some corrections or any other alternative so that i can use select query on any table name dynamically selected by user
If you don't know the schema, don't use GORP ... Why? because GORPs is a mapper, it needs a source and a target field to know how to process data, if you don't pass a target then GORP really doesn't know what to do.
However, you can do this using the standard SQL package. See this answer for more information: sql: scan row(s) with unknown number of columns (select * from ...)

Golang ORDER BY issue with MySql

I can't seem to dynamically ORDER BY with db.Select(). I've Googled without any luck...
WORKS
rows, err := db.Query("SELECT * FROM Apps ORDER BY title DESC")
DOES NOT WORK
rows, err := db.Query("SELECT * FROM Apps ORDER BY ? DESC", "title")
I'm not getting any errors, the query simply fails to order.
Placeholders ('?') can only be used to insert dynamic, escaped values for filter parameters (e.g. in the WHERE part), where data values should appear, not for SQL keywords, identifiers etc. You cannot use it to dynamically specify the ORDER BY OR GROUP BY values.
You can still do it though, for example you can use fmt.Sprintf() to assemble the dynamic query text like this:
ordCol := "title"
qtext := fmt.Sprintf("SELECT * FROM Apps ORDER BY %s DESC", ordCol)
rows, err := db.Query(qtext)
Things to keep in mind:
Doing so you will have to manually defend vs SQL injection, e.g. if the value of the column name comes from the user, you cannot accept any value and just insert it directly into the query else the user will be able to do all kinds of bad things. Trivially you should only accept letters of the English alphabet + digits + underscore ('_').
Without attempting to provide a complete, all-extensive checker or escaping function, you can use this simple regexp which only accepts English letters, digits and '_':
valid := regexp.MustCompile("^[A-Za-z0-9_]+$")
if !valid.MatchString(ordCol) {
// invalid column name, do not proceed in order to prevent SQL injection
}
Examples (try it on the Go Playground):
fmt.Println(valid.MatchString("title")) // true
fmt.Println(valid.MatchString("another_col_2")) // true
fmt.Println(valid.MatchString("it's a trap!")) // false
fmt.Println(valid.MatchString("(trap)")) // false
fmt.Println(valid.MatchString("also*trap")) // false