sqldb+config: validate maximum batch size config value

Now that the SQL query config values are configurable, we add some
validation to make sure that the user doesnt set a max batch size that
is larger than the limits for sqlite/postgres that have been determined
by the TestSQLSliceQueries test.
This commit is contained in:
Elle Mouton
2025-08-11 11:27:06 +02:00
parent ee292786b1
commit 185166b8d3
4 changed files with 67 additions and 4 deletions

View File

@@ -143,6 +143,9 @@ func (db *DB) Validate() error {
}
case SqliteBackend:
if err := db.Sqlite.Validate(); err != nil {
return err
}
case PostgresBackend:
if err := db.Postgres.Validate(); err != nil {
return err

View File

@@ -31,6 +31,15 @@ type SqliteConfig struct {
QueryConfig `group:"query" namespace:"query"`
}
// Validate checks that the SqliteConfig values are valid.
func (p *SqliteConfig) Validate() error {
if err := p.QueryConfig.Validate(true); err != nil {
return fmt.Errorf("invalid query config: %w", err)
}
return nil
}
// PostgresConfig holds the postgres database configuration.
//
//nolint:ll
@@ -42,6 +51,7 @@ type PostgresConfig struct {
QueryConfig `group:"query" namespace:"query"`
}
// Validate checks that the PostgresConfig values are valid.
func (p *PostgresConfig) Validate() error {
if p.Dsn == "" {
return fmt.Errorf("DSN is required")
@@ -53,5 +63,9 @@ func (p *PostgresConfig) Validate() error {
return fmt.Errorf("invalid DSN: %w", err)
}
if err := p.QueryConfig.Validate(false); err != nil {
return fmt.Errorf("invalid query config: %w", err)
}
return nil
}

View File

@@ -5,6 +5,18 @@ import (
"fmt"
)
const (
// maxSQLiteBatchSize is the maximum number of items that can be
// included in a batch query IN clause for SQLite. This was determined
// using the TestSQLSliceQueries test.
maxSQLiteBatchSize = 32766
// maxPostgresBatchSize is the maximum number of items that can be
// included in a batch query IN clause for Postgres. This was determined
// using the TestSQLSliceQueries test.
maxPostgresBatchSize = 65535
)
// QueryConfig holds configuration values for SQL queries.
//
//nolint:ll
@@ -18,6 +30,34 @@ type QueryConfig struct {
MaxPageSize int32 `long:"max-page-size" description:"The maximum number of items to return in a single page of results. This is used for paginated queries."`
}
// Validate checks that the QueryConfig values are valid.
func (c *QueryConfig) Validate(sqlite bool) error {
if c.MaxBatchSize <= 0 {
return fmt.Errorf("max batch size must be greater than "+
"zero, got %d", c.MaxBatchSize)
}
if c.MaxPageSize <= 0 {
return fmt.Errorf("max page size must be greater than "+
"zero, got %d", c.MaxPageSize)
}
if sqlite {
if c.MaxBatchSize > maxSQLiteBatchSize {
return fmt.Errorf("max batch size for SQLite cannot "+
"exceed %d, got %d", maxSQLiteBatchSize,
c.MaxBatchSize)
}
} else {
if c.MaxBatchSize > maxPostgresBatchSize {
return fmt.Errorf("max batch size for Postgres cannot "+
"exceed %d, got %d", maxPostgresBatchSize,
c.MaxBatchSize)
}
}
return nil
}
// DefaultQueryConfig returns a default configuration for SQL queries.
func DefaultQueryConfig() *QueryConfig {
return &QueryConfig{

View File

@@ -281,11 +281,17 @@ func TestSQLSliceQueries(t *testing.T) {
break
}
x *= 10
// If it succeeded, we expect it to be under the maximum that
// we expect for this DB.
if isSQLite {
require.LessOrEqual(t, x, maxSQLiteBatchSize,
"SQLite should not exceed 32766 parameters")
} else {
require.LessOrEqual(t, x, maxPostgresBatchSize,
"Postgres should not exceed 65535 parameters")
}
// Just to make sure that the test doesn't carry on too long,
// we assert that we don't exceed a reasonable limit.
require.LessOrEqual(t, x, 100000)
x *= 10
}
// Now that we have found the limit that the raw query can handle, we