У меня есть код, который выполняет модульное тестирование, где я готовлю базу данных для тестов (я не использую sql-go-mock), поэтому я хочу вставить возвращаемый идентификатор с помощью простого sql INSERT INTO, но по какой-то причине ошибки pgx с panic: ERROR: syntax error at or near ")" (SQLSTATE 42601)
, но запрос выполняется в консоли Goland.
Что здесь не так? Кстати, код даже не работает без ВОЗВРАЩЕНИЯ id.
Запрос, созданный строителем: INSERT INTO collections (name) VALUES (?),(?) RETURNING id
Упрощенный пример ниже
package main
import (
"context"
"fmt"
sq "github.com/Masterminds/squirrel"
"github.com/jackc/pgx/v5/pgxpool"
)
func main() {
dsn := "postgresql://user:password@localhost:5432/merge?sslmode=disable"
ctx := context.Background()
pool, err := pgxpool.New(ctx, dsn)
if err != nil {
panic(err)
}
type a struct {
ID uint
Name string
}
as := []a{{
Name: "asd",
}, {
Name: "zxc",
}}
stmt := sq.Insert("collections").Columns("name").
Values(as[0].Name).Values(as[1].Name).
Suffix("RETURNING id")
query, args, err := stmt.ToSql()
if err != nil {
panic(err)
}
err = pool.QueryRow(ctx, query, args).Scan(&as)
if err != nil {
panic(err)
}
fmt.Printf("%v", as)
}
?
не является допустимым заполнителем параметра в PostgreSQL, вместо этого PostgreSQL использует $N
, где N
— это позиция аргумента, например. $1
для первого аргумента, $2
для второго и т. д.
psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
, и тогда вы сможете использовать возвращенный конструктор psql
для построения запросов с правильным форматом заполнителя..PlaceholderFormat(sq.Dollar)
к вашему оператору sq.Insert("collections")...
.psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
// You use question marks for placeholders...
sql, _, _ := psql.Select("*").From("elephants").Where("name IN (?,?)", "Dumbo", "Verna").ToSql()
/// ...squirrel replaces them using PlaceholderFormat.
sql == "SELECT * FROM elephants WHERE name IN ($1,$2)"
/// You can retrieve id ...
query := sq.Insert("nodes").
Columns("uuid", "type", "data").
Values(node.Uuid, node.Type, node.Data).
Suffix("RETURNING \"id\"").
RunWith(m.db).
PlaceholderFormat(sq.Dollar)
query.QueryRow().Scan(&node.id)
Пример взят из READMEsquirrel
.
Вот код, измененный в соответствии с ответом @mkopriva.
package main
import (
"context"
"fmt"
sq "github.com/Masterminds/squirrel"
"github.com/jackc/pgx/v5/pgxpool"
)
func main() {
dsn := "postgresql://user:password@localhost:5432/merge?sslmode=disable"
ctx := context.Background()
pool, err := pgxpool.New(ctx, dsn)
if err != nil {
panic(err)
}
defer pool.Close()
var ids []int
type a struct {
ID uint
Name string
}
as := []a{{
Name: "asd",
}, {
Name: "zxc",
}}
stmt := sq.Insert("collections").Columns("name").
Values(as[0].Name).Values(as[1].Name).
Suffix("RETURNING id").PlaceholderFormat(sq.Dollar)
query, args, err := stmt.ToSql()
fmt.Printf("%v\n", args)
rows, err := pool.Query(ctx, query, args...)
if err != nil {
panic(err)
}
defer rows.Close()
for rows.Next() {
var id int
if err := rows.Scan(&id); err != nil {
panic(err)
}
ids = append(ids, id)
}
if err := rows.Err(); err != nil {
panic(err)
}
fmt.Printf("%v\n", ids)
}