{"record":{"id":"72ebc1053a90f2f4","repo":"t8y2/dbx","slug":"table-read-requires-a-select-query","errorCode":null,"errorMessage":"table read requires a SELECT query","messagePattern":"table read requires a SELECT query","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/oracle-go/main.go","lineNumber":3874,"sourceCode":"}\n\nfunc (s *server) storeQuerySession(session *querySession) string {\n\ts.nextSessionID++\n\tsessionID := fmt.Sprintf(\"oracle-go-%d\", s.nextSessionID)\n\ts.sessions[sessionID] = session\n\treturn sessionID\n}\n\nfunc (s *server) startTableRead(opts queryOptions, pageSize int) (queryPageResult, error) {\n\tstart := time.Now()\n\tif strings.TrimSpace(opts.Schema) != \"\" && !s.hasManualTransaction() {\n\t\tif err := s.setSchema(opts.Schema); err != nil {\n\t\t\treturn queryPageResult{}, err\n\t\t}\n\t}\n\tsqlText := trimStatementSQL(opts.SQL)\n\tif !isQuerySQL(sqlText) {\n\t\treturn queryPageResult{}, errors.New(\"table read requires a SELECT query\")\n\t}\n\tresult, session, err := s.runPagedOracleSelect(sqlText, opts, pageSize, start)\n\tif err != nil {\n\t\treturn queryPageResult{}, err\n\t}\n\tif session != nil {\n\t\tsessionID := s.storeTableReadSession(session)\n\t\tresult.SessionID = &sessionID\n\t}\n\treturn result, nil\n}\n\nfunc (s *server) fetchTableReadPage(sessionID string, pageSize int) (queryPageResult, error) {\n\tsession := s.tableReadSessions[sessionID]\n\tif session == nil {\n\t\treturn queryPageResult{Columns: []string{}, ColumnTypes: []string{}, Rows: [][]any{}, SessionID: nil, HasMore: false}, nil\n\t}\n\tresult, err := readQuerySessionPage(session, pageSize)","sourceCodeStart":3856,"sourceCodeEnd":3892,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/oracle-go/main.go#L3856-L3892","documentation":"The Oracle driver's table-read path only executes SELECT statements, since it pages through a live server-side cursor (runPagedOracleSelect). startTableRead validates the trimmed SQL with isQuerySQL and refuses anything that is not a query. This protects the paged-read machinery, which cannot handle DML/DDL that returns no row set.","triggerScenarios":"Calling the table-read/paged-query API with opts.SQL set to an INSERT, UPDATE, DELETE, MERGE, DDL statement (CREATE/ALTER/DROP), or an empty/whitespace string, or a SELECT-less statement that the isQuerySQL heuristic does not recognize as a query.","commonSituations":"Developers reusing a generic 'run SQL' wrapper and pointing it at the table-read endpoint; passing a script with trailing comments that defeats the SELECT-prefix heuristic; trying to mutate data through a read-oriented paging API.","solutions":["Rewrite the statement as a SELECT (the table-read API is read-only paging over a cursor).","Run DML/DDL through the driver's generic execute/non-query API instead of the table-read path.","Ensure the SQL literally starts with a SELECT clause recognized by isQuerySQL and contains no leading comments/whitespace tricks that hide it."],"exampleFix":"// before\nres, err := client.TableRead(ctx, QueryOptions{SQL: \"DELETE FROM orders WHERE id = 7\"})\n// after\nres, err := client.Execute(ctx, \"DELETE FROM orders WHERE id = 7\") // non-query API\n// or for reads:\nres, err := client.TableRead(ctx, QueryOptions{SQL: \"SELECT * FROM orders WHERE id = 7\"})","handlingStrategy":"validation","validationCode":"sqlText := strings.TrimSpace(opts.SQL)\nif !strings.HasPrefix(strings.ToUpper(sqlText), \"SELECT\") {\n    return fmt.Errorf(\"table read needs SELECT, got: %.40s\", sqlText)\n}","typeGuard":"func isSelectQuery(sql string) bool {\n    s := strings.TrimSpace(strings.TrimLeft(strings.TrimSpace(sql), \"(--/* \\t\\n\"))\n    return strings.HasPrefix(strings.ToUpper(s), \"SELECT\")\n}","tryCatchPattern":null,"preventionTips":["Route DML/DDL through the execute API, never the table-read API.","Sanitize/normalize SQL (strip comments) before the SELECT check.","Write a unit test asserting the paged-read path rejects non-SELECT statements."],"tags":["oracle","sql","validation","read-only"],"backgroundTag":"non-select-statement-rejected","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}