bytebase/bytebase · error

pseudo constant select: expected 1 statement, got %d

Error message

pseudo constant select: expected 1 statement, got %d

What it means

pseudoConstantSelect expects the synthetic `SELECT ...` string it builds to parse into exactly one statement. Since the string is constructed internally, more than one statement can only mean a target expression contained a statement separator. This error reports the actual statement count.

Source

Thrown at backend/plugin/parser/pg/query_span_loader_pseudo.go:207

// is emitted so the SELECT is well-formed.
func pseudoConstantSelect(columnNames []string) (*ast.SelectStmt, error) {
	var targets []string
	for _, col := range columnNames {
		if col == "" {
			continue
		}
		targets = append(targets, "NULL::text AS "+quoteIdent(col))
	}
	if len(targets) == 0 {
		targets = []string{"NULL::text"}
	}
	sql := "SELECT " + strings.Join(targets, ", ")
	stmts, err := ParsePg(sql)
	if err != nil {
		return nil, errors.Wrap(err, "parse pseudo constant select")
	}
	if len(stmts) != 1 {
		return nil, errors.Errorf("pseudo constant select: expected 1 statement, got %d", len(stmts))
	}
	sel, ok := stmts[0].AST.(*ast.SelectStmt)
	if !ok {
		return nil, errors.Errorf("pseudo constant select: expected SelectStmt, got %T", stmts[0].AST)
	}
	return sel, nil
}

// functionArgCountFromSignature parses a signature string like
// "my_func(integer, text)" and returns the number of arguments. A signature
// with no parentheses or an empty argument list returns 0.
func functionArgCountFromSignature(signature string) int {
	openIdx := strings.Index(signature, "(")
	if openIdx < 0 {
		return 0
	}
	closeIdx := strings.LastIndex(signature, ")")
	if closeIdx < 0 || closeIdx <= openIdx {

View on GitHub (pinned to 1870550677)

Solutions

  1. Sanitize or reject target expressions containing ';' before building the SQL
  2. Log the individual targets to find which one embeds a separator
  3. Re-sync metadata to restore clean column expressions
  4. Prefer quoting identifiers so special characters are escaped

Example fix

// before
targets := []string{"a; b"} // produces 2 statements
// after
targets := []string{"a", "b"} // "SELECT a, b"
Defensive patterns

Strategy: validation

Validate before calling

for _, t := range targets {
	if strings.Contains(t, ";") {
		return errors.Errorf("target %q contains statement separator", t)
	}
}

Type guard

func singleStatementTargets(targets []string) bool {
	for _, t := range targets { if strings.Contains(t, ";") { return false } }
	return true
}

Try / catch

sel, err := pseudoConstantSelect(targets)
if err != nil && strings.Contains(err.Error(), "expected 1 statement") {
	return nil, fmt.Errorf("sanitize targets %v: %w", targets, err)
}

Prevention

When it happens

Trigger: A target string passed from pseudoViewStmt/pseudoCreateTableAsStmt contains a semicolon, so "SELECT a; b" parses as two statements instead of one.

Common situations: Unsanitized metadata column expressions containing semicolons; concatenated target lists built incorrectly upstream.

Related errors


AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06). Data as JSON: /api/errors/bc1d03745a68d3c0. Report an issue: GitHub.