{"record":{"id":"deafabca8bae4634","repo":"bytebase/bytebase","slug":"expected-exactly-1-statement-got-d-deafab","errorCode":null,"errorMessage":"expected exactly 1 statement, got %d","messagePattern":"expected exactly 1 statement, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/plugin/parser/tsql/query_span_extractor_omni.go","lineNumber":48,"sourceCode":"\n// getOmniQuerySpan is the public entry point. Mirrors the ANTLR getQuerySpan flow.\nfunc (q *omniQuerySpanExtractor) getOmniQuerySpan(ctx context.Context, statement string) (*base.QuerySpan, error) {\n\tq.ctx = ctx\n\tq.source = statement\n\n\tstmts, err := ParseTSQLOmni(statement)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(stmts) == 0 {\n\t\treturn &base.QuerySpan{\n\t\t\tType:          base.Select,\n\t\t\tSourceColumns: make(base.SourceColumnSet),\n\t\t\tResults:       []base.QuerySpanResult{},\n\t\t}, nil\n\t}\n\tif len(stmts) != 1 {\n\t\treturn nil, errors.Errorf(\"expected exactly 1 statement, got %d\", len(stmts))\n\t}\n\n\troot := stmts[0].AST\n\tif root == nil {\n\t\t// An empty statement. Match ANTLR's zero-AST behavior.\n\t\treturn &base.QuerySpan{\n\t\t\tType:          base.Select,\n\t\t\tSourceColumns: make(base.SourceColumnSet),\n\t\t\tResults:       []base.QuerySpanResult{},\n\t\t}, nil\n\t}\n\tif _, isGo := root.(*ast.GoStmt); isGo {\n\t\t// A bare \"GO\" batch separator. ANTLR discards it and returns an empty\n\t\t// Select span; match that.\n\t\treturn &base.QuerySpan{\n\t\t\tType:          base.Select,\n\t\t\tSourceColumns: make(base.SourceColumnSet),\n\t\t\tResults:       []base.QuerySpanResult{},","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/plugin/parser/tsql/query_span_extractor_omni.go#L30-L66","documentation":"getOmniQuerySpan parses the SQL text via the omni parser and requires exactly one statement to compute a query span. If the parser returned zero or more than one statement (batch input with multiple statements separated by semicolons, or an unexpected parse result), it cannot determine a single root span and returns this error. Zero-statement and empty-AST cases are handled explicitly before this check.","triggerScenarios":"Passing a TSQL batch containing multiple semicolon-separated statements to the query span extractor, or any input the omni parser splits into more than one AST root.","commonSituations":"Users submitting multi-statement scripts (e.g. `SET NOCOUNT ON; SELECT ...;`) for data-care/lineage analysis, or migration scripts pasted in whole instead of per-statement analysis.","solutions":["Split the input into individual statements and call the extractor once per statement, aggregating spans yourself.","Strip non-query prologue statements (SET options, DECLARE) before span extraction, or run extraction only on the SELECT/DML statements.","If a single statement is expected but the parser returned several, verify there are no stray semicolons or GO batch separators."],"exampleFix":"// before: extract the whole batch\nspan, err := GetQuerySpan(batchSQL) // \"expected exactly 1 statement, got 3\"\n// after: split and extract per statement\nfor _, stmt := range splitStatements(batchSQL) {\n    span, err := GetQuerySpan(stmt)\n}","handlingStrategy":"validation","validationCode":"stmts := splitStatements(sql)\nif len(stmts) != 1 {\n    return fmt.Errorf(\"span extraction needs a single statement, got %d\", len(stmts))\n}","typeGuard":null,"tryCatchPattern":"span, err := getOmniQuerySpan(content)\nif err != nil && strings.Contains(err.Error(), \"expected exactly 1 statement\") {\n    for _, stmt := range splitStatements(content) {\n        span, err = getOmniQuerySpan(stmt)\n    }\n}","preventionTips":["Split batches on semicolons/GO separators and analyze one statement at a time.","Strip SET/DECLARE prologue statements before requesting a query span.","Restrict input endpoints (edit-review, lineage) to single-statement SQL."],"tags":["tsql","query-span","parser","batch-statements"],"backgroundTag":"invalid-argument-value","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}