Home > database >  How to parametrize a dynamic query in Go
How to parametrize a dynamic query in Go

Time:01-03

Users can request product prices based on a number of different criteria, which will result in it potentially accessing different columns in a table. I'm looping through the requested products and building a bunch of queries, but am running into some trouble.

Running them one by one and combining the results takes a much longer time than unionizing them. So I tried building the query like follows, which works and is fast, but is now susceptible to injection.

Is there a better way to do this without the Union? Or is there a simple way I could parametrize a dynamic query like this?

    var fullQuery string
    var counter int
    for i, d:= range dataMap{
    if counter != 0 {
        fullQuery = fullQuery   " UNION "
    }
    var records string
    for _, p := range d{
        records = records   `'`   string(p)   `',`
    }
    recordLength:= len(records)
    if recordLength> 0 && records [recordLength-1] == ',' {
        records = records[:recordLength-1]
    }
    counter  
    fullQuery = fullQuery   fmt.Sprintf(`
SELECT 
    price_` fmt.Sprint(p.type) ` as price,                
  FROM products
  WHERE products.id in (%s) and products.store= %s
  
`, records, p.store)

}

err := sqlx.Select(db, &dataStruct, fullQuery)

So, in some situations, I might have the following query:

SELECT 
    price_` fmt.Sprint(p.type) ` as price,                
  FROM products
  WHERE products.id in (%s) and products.store= %s

And in others (depending on the request), I might have something like this:

SELECT 
    price_` fmt.Sprint(p.type) ` as price,                
  FROM products
  WHERE products.id in ('testid1', 'testid2') and products.store= 2
UNION
SELECT 
    price_` fmt.Sprint(p.type) ` as price,                
  FROM products
  WHERE products.id in ('testid3', 'testid4') and products.store= 1

If I knew for sure what the query was, I would just use $1, $2, etc.., but I don't think I can here because I don't know how many parameters there will be and they all need to be different.

CodePudding user response:

Figured it out, rough untested example of how I ended up doing it in case anyone else runs into this.

 var counter int = 1
 var parameters []interface{}

 for _, d:= range data{
    if counter != 1 {
        fullQuery = fullQuery   " UNION "
    }
    fullQuery = fullQuery   fmt.Sprintf(`
SELECT 
    price_` fmt.Sprint(d.type) ` as price,                
  FROM products
  WHERE products.id = ANY($%v) and products.store= $%d
  
`, counter, counter 1)
   counter =2
   parameters = append(parameters, pq.Array(d.ids), d.store)

}

err := sqlx.Select(db, &dataStruct, fullQuery, parameters...)
  • Related