Prepare creates a prepared statement with name and sql. sql can contain placeholders for bound parameters. These placeholders are referenced positionally as $1, $2, etc. name can be used instead of sql with [Conn.Query], [Conn.QueryRow], and [Conn.Exec] to execute the statement. It can also be used
(ctx context.Context, name, sql string)
| 317 | // Prepare is idempotent; i.e. it is safe to call Prepare multiple times with the same name and sql arguments. This |
| 318 | // allows a code path to Prepare and Query/Exec without concern for if the statement has already been prepared. |
| 319 | func (c *Conn) Prepare(ctx context.Context, name, sql string) (sd *pgconn.StatementDescription, err error) { |
| 320 | if c.failedDescribeStatement != "" { |
| 321 | err = c.Deallocate(ctx, c.failedDescribeStatement) |
| 322 | if err != nil { |
| 323 | return nil, fmt.Errorf("failed to deallocate previously failed statement %q: %w", c.failedDescribeStatement, err) |
| 324 | } |
| 325 | c.failedDescribeStatement = "" |
| 326 | } |
| 327 | |
| 328 | if c.prepareTracer != nil { |
| 329 | ctx = c.prepareTracer.TracePrepareStart(ctx, c, TracePrepareStartData{Name: name, SQL: sql}) |
| 330 | } |
| 331 | |
| 332 | if name != "" { |
| 333 | var ok bool |
| 334 | if sd, ok = c.preparedStatements[name]; ok && sd.SQL == sql { |
| 335 | if c.prepareTracer != nil { |
| 336 | c.prepareTracer.TracePrepareEnd(ctx, c, TracePrepareEndData{AlreadyPrepared: true}) |
| 337 | } |
| 338 | return sd, nil |
| 339 | } |
| 340 | } |
| 341 | |
| 342 | if c.prepareTracer != nil { |
| 343 | defer func() { |
| 344 | c.prepareTracer.TracePrepareEnd(ctx, c, TracePrepareEndData{Err: err}) |
| 345 | }() |
| 346 | } |
| 347 | |
| 348 | var psName, psKey string |
| 349 | if name == sql { |
| 350 | digest := sha256.Sum256([]byte(sql)) |
| 351 | psName = "stmt_" + hex.EncodeToString(digest[0:24]) |
| 352 | psKey = sql |
| 353 | } else { |
| 354 | psName = name |
| 355 | psKey = name |
| 356 | } |
| 357 | |
| 358 | sd, err = c.pgConn.Prepare(ctx, psName, sql, nil) |
| 359 | if err != nil { |
| 360 | var pErr *pgconn.PrepareError |
| 361 | if errors.As(err, &pErr) { |
| 362 | c.failedDescribeStatement = psKey |
| 363 | } |
| 364 | return nil, err |
| 365 | } |
| 366 | |
| 367 | if psKey != "" { |
| 368 | c.preparedStatements[psKey] = sd |
| 369 | } |
| 370 | |
| 371 | return sd, nil |
| 372 | } |
| 373 | |
| 374 | // Deallocate releases a prepared statement. Calling Deallocate on a non-existent prepared statement will succeed. |
| 375 | func (c *Conn) Deallocate(ctx context.Context, name string) error { |
no test coverage detected