Заместители ('?'
) може да се използва само за вмъкване на динамични, екранирани стойности за параметрите на филтъра (напр. в WHERE
част), където трябва да се показват стойностите на данните, а не за SQL ключови думи, идентификатори и т.н. Не можете да го използвате за динамично определяне на ORDER BY
ИЛИ ГРУПИРАНЕ ПО
стойности.
Все пак можете да го направите, например можете да използвате fmt.Sprintf()код>
за да съберете текста на динамичната заявка по следния начин:
ordCol := "title"
qtext := fmt.Sprintf("SELECT * FROM Apps ORDER BY %s DESC", ordCol)
rows, err := db.Query(qtext)
Неща, които трябва да имате предвид:
По този начин ще трябва ръчно да защитавате срещу SQL инжекция, напр. ако стойността на името на колоната идва от потребителя, не можете да приемете никаква стойност и просто да я вмъкнете директно в заявката, в противен случай потребителят ще може да прави всякакви лоши неща. Тривиално трябва да приемате само букви от английската азбука + цифри + долно черти ('_'
).
Без да се опитвате да предоставите пълна, цялостна функция за проверка или екраниране, можете да използвате този прост регулярен израз, който приема само английски букви, цифри и '_'
:
valid := regexp.MustCompile("^[A-Za-z0-9_]+$")
if !valid.MatchString(ordCol) {
// invalid column name, do not proceed in order to prevent SQL injection
}
Примери (опитайте го на 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