Export exports the SQL query result.
(ctx context.Context, req *connect.Request[v1pb.ExportRequest])
| 958 | |
| 959 | // Export exports the SQL query result. |
| 960 | func (s *SQLService) Export(ctx context.Context, req *connect.Request[v1pb.ExportRequest]) (*connect.Response[v1pb.ExportResponse], error) { |
| 961 | request := req.Msg |
| 962 | // Prehandle export from issue. |
| 963 | if strings.HasPrefix(request.Name, common.ProjectNamePrefix) { |
| 964 | response, err := s.doExportFromIssue(ctx, request.Name) |
| 965 | if err != nil { |
| 966 | return nil, err |
| 967 | } |
| 968 | return connect.NewResponse(response), nil |
| 969 | } |
| 970 | |
| 971 | // Prepare related message. |
| 972 | user, instance, database, err := s.prepareRelatedMessage(ctx, request.Name) |
| 973 | if err != nil { |
| 974 | return nil, err |
| 975 | } |
| 976 | |
| 977 | statement := request.Statement |
| 978 | // In Redshift datashare, Rewrite query used for parser. |
| 979 | if database.Metadata.GetDatashare() { |
| 980 | statement = strings.ReplaceAll(statement, fmt.Sprintf("%s.", database.DatabaseName), "") |
| 981 | } |
| 982 | |
| 983 | // requireExport=true narrows the CEL filter to grants with export=true, |
| 984 | // so a tied unmask-only grant can't shadow a separately-active export |
| 985 | // grant via slice order (PR #20491 bot review). |
| 986 | accessGrant := s.preCheckAccess(ctx, request.Statement, instance, database, true /* requireExport */) |
| 987 | |
| 988 | // Validate the request. |
| 989 | // New query ACL experience. |
| 990 | if instance.Metadata.GetEngine() != storepb.Engine_MYSQL { |
| 991 | if err := validateQueryRequest(instance, statement); err != nil { |
| 992 | return nil, err |
| 993 | } |
| 994 | } |
| 995 | |
| 996 | resolvedDataSourceID, err := resolveDataSourceID(ctx, instance, request.DataSourceId, statement, false) |
| 997 | if err != nil { |
| 998 | return nil, err |
| 999 | } |
| 1000 | |
| 1001 | dataSource, err := checkAndGetDataSourceQueriable(ctx, s.store, s.licenseService, database, resolvedDataSourceID) |
| 1002 | if err != nil { |
| 1003 | return nil, err |
| 1004 | } |
| 1005 | |
| 1006 | // Same cross-database guardrail as Query: the JIT grant authorizes only |
| 1007 | // its target databases, so span-level ACL still runs and only the |
| 1008 | // granted targets are exempted from IAM. See PR #20487 review. |
| 1009 | optionalAccessCheck := s.accessCheckWithGrant(accessGrant) |
| 1010 | skipMasking := false |
| 1011 | if accessGrant != nil { |
| 1012 | skipMasking = accessGrant.Payload.Unmask |
| 1013 | } |
| 1014 | bytes, duration, exportErr := doExport(ctx, s.store, s.dbFactory, s.licenseService, request, user, instance, database, optionalAccessCheck, s.schemaSyncer, dataSource, skipMasking) |
| 1015 | |
| 1016 | s.createQueryHistory(database, store.QueryHistoryTypeExport, statement, user.Email, duration, exportErr) |
| 1017 |
nothing calls this directly
no test coverage detected