{"record":{"id":"424940bc6ff2a718","repo":"bytebase/bytebase","slug":"left-and-right-query-span-result-length-mismatch","errorCode":null,"errorMessage":"left and right query span result length mismatch: %d != %d","messagePattern":"left and right query span result length mismatch: (.+?) != (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/plugin/parser/plsql/query_span_extractor_omni.go","lineNumber":364,"sourceCode":"\t}\n\tright, err := q.extractOmniSelect(stmt.Rarg)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn mergeOmniSetTableSources(left, right)\n}\n\nfunc mergeOmniSetTableSources(left, right base.TableSource) (base.TableSource, error) {\n\tif left == nil {\n\t\treturn right, nil\n\t}\n\tif right == nil {\n\t\treturn left, nil\n\t}\n\tleftResults := left.GetQuerySpanResult()\n\trightResults := right.GetQuerySpanResult()\n\tif len(leftResults) != len(rightResults) {\n\t\treturn nil, errors.Errorf(\"left and right query span result length mismatch: %d != %d\", len(leftResults), len(rightResults))\n\t}\n\tresult := make([]base.QuerySpanResult, 0, len(leftResults))\n\tfor i, leftResult := range leftResults {\n\t\tsourceColumns, _ := base.MergeSourceColumnSet(leftResult.SourceColumns, rightResults[i].SourceColumns)\n\t\tresult = append(result, base.QuerySpanResult{\n\t\t\tName:          leftResult.Name,\n\t\t\tSourceColumns: sourceColumns,\n\t\t\tIsPlainField:  false,\n\t\t})\n\t}\n\treturn &base.PseudoTable{Columns: result}, nil\n}\n\nfunc (q *omniQuerySpanExtractor) extractOmniCTE(cte *oracleast.CTE) (*base.PseudoTable, error) {\n\tif cte == nil {\n\t\treturn nil, nil\n\t}\n\tname := cte.Name","sourceCodeStart":346,"sourceCodeEnd":382,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/plugin/parser/plsql/query_span_extractor_omni.go#L346-L382","documentation":"Set operations (UNION, INTERSECT, MINUS) require both branches to yield the same number of output columns; mergeOmniSetTableSources throws when the left and right QuerySpanResult lists differ in length. This mirrors Oracle's ORA-01789 class of errors at the lineage-analysis level.","triggerScenarios":"extractOmniSetSelect or extractOmniCTE analyzing a UNION/UNION ALL/INTERSECT/MINUS whose left and right SELECT lists have different column counts — often after * expansion resolves to different widths on each side.","commonSituations":"Hand-written UNION queries with mismatched SELECT lists; SELECT * on tables whose schemas diverged (column added to one table only); dynamically generated SQL assembling branches independently.","solutions":["Fix the SQL so both set-operation branches select the same number of columns","Replace SELECT * in union branches with explicit, aligned column lists","Re-check the referenced table schemas — a recent column addition may have desynchronized the branches","If analysis-side, validate branch arity before merging and emit a user-facing SQL error instead of an internal one"],"exampleFix":"// before\nSELECT id, name FROM a UNION SELECT id FROM b\n// after\nSELECT id, name FROM a UNION SELECT id, name FROM b","handlingStrategy":"validation","validationCode":"if len(leftResults) != len(rightResults) { return errors.New(\"union branches must have equal column counts\") }","typeGuard":null,"tryCatchPattern":"src, err := extractor.GetQuerySpan(ctx, sql)\nif err != nil && strings.Contains(err.Error(), \"result length mismatch\") {\n    return nil, fmt.Errorf(\"set-operation branches differ in column count: %w\", err)\n}","preventionTips":["Use explicit column lists in UNION/INTERSECT/MINUS branches","Re-verify union arity after any referenced-table schema change","Add a pre-flight query linter that checks set-operation column counts"],"tags":["plsql","union","column-count"],"backgroundTag":"shape-mismatch","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"}