getQueryType classifies a single parsed Trino statement. It returns the base.QueryType plus a bool that is true only for EXPLAIN ANALYZE. EXPLAIN ANALYZE actually executes the inner query, so the legacy plugin reported it as base.Select (not base.Explain) with the flag set; we preserve that. A plai
(node ast.Node)
| 24 | // node is an omni AST node (one of the *parser.*Stmt types). A nil node yields |
| 25 | // (QueryTypeUnknown, false). |
| 26 | func getQueryType(node ast.Node) (base.QueryType, bool) { |
| 27 | if node == nil { |
| 28 | return base.QueryTypeUnknown, false |
| 29 | } |
| 30 | switch n := node.(type) { |
| 31 | case *parser.QueryStmt: |
| 32 | return base.Select, false |
| 33 | case *parser.ExplainStmt: |
| 34 | if n.Analyze { |
| 35 | // EXPLAIN ANALYZE EXECUTES the inner statement (oracle-confirmed: |
| 36 | // Trino 481 runs it), so its read-only-ness is the inner statement's, |
| 37 | // not unconditionally read-only. Report the inner type and flag |
| 38 | // isAnalyze so validateQuery rejects EXPLAIN ANALYZE of a non-SELECT |
| 39 | // (e.g. EXPLAIN ANALYZE UPDATE, which would otherwise run a write |
| 40 | // through the read-only SQL-editor gate). |
| 41 | innerType, _ := getQueryType(n.Statement) |
| 42 | return innerType, true |
| 43 | } |
| 44 | return base.Explain, false |
| 45 | case *parser.ShowStmt, |
| 46 | *parser.DescribeInputStmt, *parser.DescribeOutputStmt: |
| 47 | return base.SelectInfoSchema, false |
| 48 | case *parser.SetSessionStmt, *parser.ResetSessionStmt, |
| 49 | *parser.SetSessionAuthorizationStmt, *parser.ResetSessionAuthorizationStmt, |
| 50 | *parser.SetPathStmt, *parser.SetRoleStmt, *parser.SetTimeZoneStmt, |
| 51 | *parser.UseStmt: |
| 52 | // Session-state statements were classified read-only (base.Select) by the |
| 53 | // legacy listener (EnterSetSession / EnterResetSession). USE is also a |
| 54 | // session-scoped no-op for read purposes. Keep them read-only. |
| 55 | return base.Select, false |
| 56 | case *parser.InsertStmt, *parser.UpdateStmt, *parser.DeleteStmt, |
| 57 | *parser.MergeStmt, *parser.TruncateStmt, *parser.CallStmt: |
| 58 | return base.DML, false |
| 59 | } |
| 60 | // Everything else (CREATE/ALTER/DROP/COMMENT/GRANT/REVOKE/ANALYZE/ |
| 61 | // transaction control/prepared-statement admin/...) is DDL. This is the safe |
| 62 | // upper bound for ACL purposes and matches the legacy listener's |
| 63 | // "everything else is DDL" default. |
| 64 | return base.DDL, false |
| 65 | } |
| 66 | |
| 67 | // queryTypeFromText parses statement and classifies its single top-level |
| 68 | // statement, applying the legacy statement-text system-schema promotion: a |
no outgoing calls