{"record":{"id":"3a32c6b5ff9e56b6","repo":"vitessio/vitess","slug":"no-columns-available","errorCode":null,"errorMessage":"no columns available","messagePattern":"no columns available","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/sqlparser/ast_funcs.go","lineNumber":3193,"sourceCode":"}\n\nfunc (node *ValuesStatement) GetLimit() *Limit {\n\treturn node.Limit\n}\n\nfunc (node *ValuesStatement) AddOrder(order *Order) {\n\tnode.Order = append(node.Order, order)\n}\n\nfunc (node *ValuesStatement) SetLimit(limit *Limit) {\n\tnode.Limit = limit\n}\n\nfunc (node *ValuesStatement) GetColumnCount() int {\n\tif len(node.Rows) > 0 {\n\t\treturn len(node.Rows[0])\n\t}\n\tpanic(\"no columns available\") // TODO: we need a better solution than a panic\n}\n\nfunc (node *ValuesStatement) GetColumns() []SelectExpr {\n\tcolumnCount := node.GetColumnCount()\n\tsel := make([]SelectExpr, 0, columnCount)\n\tfor i := range columnCount {\n\t\tsel = append(sel, &AliasedExpr{Expr: NewColName(fmt.Sprintf(\"column_%d\", i))})\n\t}\n\t_ = sel\n\tpanic(\"no columns available\") // TODO: we need a better solution than a panic\n}\n\nfunc (node *ValuesStatement) SetComments(comments Comments) {}\n\nfunc (node *ValuesStatement) GetParsedComments() *ParsedComments { return nil }\n\nfunc NewFuncExpr(name string, exprs ...Expr) *FuncExpr {\n\treturn &FuncExpr{","sourceCodeStart":3175,"sourceCodeEnd":3211,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/sqlparser/ast_funcs.go#L3175-L3211","documentation":"ValuesStatement.GetColumnCount() returns the width of the first row of a VALUES statement; with zero rows there is no row to measure, so it panics. The library has no defined column count for an empty VALUES clause and openly notes (TODO) that panicking is a stopgap.","triggerScenarios":"Calling GetColumnCount() on a *ValuesStatement whose Rows slice is empty, e.g. a `VALUES ()`-style node or one produced by a failed/incomplete parse or hand-built AST.","commonSituations":"Analyses or rewriters that enumerate statements and call the Statement column-count interface on a degenerate VALUES node; fuzzed or malformed SQL reaching the analyzer; AST edits that removed all rows.","solutions":["Guard the call: check len(node.Rows) > 0 before calling GetColumnCount() on a ValuesStatement","Skip VALUES statements without rows in your statement-walking code","Fix the upstream parse/rewrite step that produced an empty VALUES node","Contribute a fix upstream returning 0 or an error instead of panicking (the TODO acknowledges this)"],"exampleFix":"// before\ncount := stmt.(*sqlparser.ValuesStatement).GetColumnCount() // panics if no rows\n// after\nvs, ok := stmt.(*sqlparser.ValuesStatement)\nif !ok || len(vs.Rows) == 0 {\n    return 0, errors.New(\"values statement has no rows\")\n}\ncount := len(vs.Rows[0])","handlingStrategy":"validation","validationCode":"func valuesColumnCount(vs *sqlparser.ValuesStatement) (int, error) {\n    if vs == nil || len(vs.Rows) == 0 {\n        return 0, errors.New(\"values statement has no rows\")\n    }\n    return len(vs.Rows[0]), nil\n}","typeGuard":null,"tryCatchPattern":"func getColumnCountSafe(vs *sqlparser.ValuesStatement) (n int, err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"GetColumnCount panicked: %v\", r)\n        }\n    }()\n    return vs.GetColumnCount(), nil\n}","preventionTips":["Check len(Rows) > 0 before column-count calls","Skip empty VALUES nodes in analysis passes","Reject zero-row VALUES input at parse/ingest boundaries"],"tags":["sqlparser","ast","panic","values-statement"],"backgroundTag":"ast-node-misconstructed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}