0

I want to make dynamic sql in GoLang and I cant seem to find the correct way to do it.

Basically, I just want to do:

query := "SELECT id, email, something FROM User"

var paramValues []string
filterString := ""

if userParams.Name != "" {
    paramString += " WHERE id = ?"
    paramValues = append(paramValues, userParams.Name)
}

if userParams.UserID != "" {
    if len(paramString) > 0 {
        paramString += " AND"
    } else {
        paramString += " WHERE"
    }

    paramString += " email = ?"
    paramValues = append(paramValues, userParams.UserID)
}
stmtOut, err := db.Prepare(query + paramString)

err = stmtOut.QueryRow(paramValues).Scan(&id, &email, &something)

Related to building a dynamic query in mysql and golang

I've been unable to find a solid way to do this that doesn't allow sql injection. The issue with my above solution is that QueryRow() does not take a []string as a parameter.

I want to protect from SQL Injection, so fmt.Sprintf doesn't really solve the problem.

This way I can allow searches on user using either the ID or Email, and I will also use this logic for different objects with more searchable fields.

I'm using go-sql-driver/mysql

1 Answer 1

2

Here's something which I can run on my local machine (go1.8 linux/amd64 and current GO MySQL driver 1.3).

Couple of ways are demonstrated.

package main

import (
    "database/sql"
    "log"

    _ "github.com/go-sql-driver/mysql"

    "fmt"
)

// var db *sql.DB
// var err error

/*
Database Name/Schema : Test123
Table Name: test
Table Columns and types:
number INT (PRIMARY KEY)
cube INT
*/

func main() {
    //Username root, password root
    db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/Test123?charset=utf8")

    if err != nil {
        fmt.Println(err) // needs proper handling as per app requirement
        return
    }
    defer db.Close()

    err = db.Ping()
    if err != nil {
        fmt.Println(err) // needs proper handling as per app requirement
        return
    }

    //Prepared statement for inserting data
    stmtIns, err := db.Prepare("INSERT INTO test VALUES( ?, ? )") // ? = placeholders
    if err != nil {
        panic(err.Error()) // needs proper handling as per app requirement
    }
    defer stmtIns.Close()

    //Insert cubes of 1- 10 numbers

    for i := 1; i < 10; i++ {
        _, err = stmtIns.Exec(i, (i * i * i)) // Insert tuples (i, i^3)
        if err != nil {
            panic(err.Error()) // proper error handling instead of panic in your app
        }
    }

    num := 3

    // Select statement

    dataEntity := "cube"
    condition := "WHERE number=? AND cube > ?"
    finalStatement := "SELECT " + dataEntity + " FROM test " + condition
    cubeLowerLimit := 10

    var myCube int
    err = db.QueryRow(finalStatement, num, cubeLowerLimit).Scan(&myCube)
    switch {
    case err == sql.ErrNoRows:
        log.Printf("No row with this number %d", num)
    case err != nil:
        log.Fatal(err)
    default:
        fmt.Printf("Cube for %d is %d\n", num, myCube)
    }

    var cubenum int

    // //Prepared statement for reading data
    stmtRead, err := db.Prepare(finalStatement)
    if err != nil {
        panic(err.Error()) // needs proper err handling
    }
    defer stmtRead.Close()

    // Query for cube of 5
    num = 5
    err = stmtRead.QueryRow(num, cubeLowerLimit).Scan(&cubenum)
    switch {
    case err == sql.ErrNoRows:
        log.Printf("No row with this number %d", num)
    case err != nil:
        log.Fatal(err)
    default:
        fmt.Printf("Cube number for %d is %d\n", num, cubenum)
    }

}

If you run it subsequent times, you need to delete the rows in the database so that the inserts won't create a panic (or alternatively change the insert rows code so that it doesn't panic). I haven't tried it on Google App Engine. Hope this helps.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.