diff --git a/pkg/server/combined_statement_stats.go b/pkg/server/combined_statement_stats.go index 18d65a9d633f..423825157766 100644 --- a/pkg/server/combined_statement_stats.go +++ b/pkg/server/combined_statement_stats.go @@ -21,7 +21,6 @@ import ( "github.com/cockroachdb/cockroach/pkg/settings/cluster" "github.com/cockroachdb/cockroach/pkg/sql" "github.com/cockroachdb/cockroach/pkg/sql/appstatspb" - "github.com/cockroachdb/cockroach/pkg/sql/parser" "github.com/cockroachdb/cockroach/pkg/sql/sem/catconstants" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" @@ -732,15 +731,7 @@ func getTotalStatementDetails( return statement, serverError(ctx, err) } - queryTree, err := parser.ParseOne(aggregatedMetadata.Query) - if err != nil { - return statement, serverError(ctx, err) - } - cfg := tree.DefaultPrettyCfg() - cfg.Align = tree.PrettyAlignOnly - cfg.LineWidth = tree.ConsoleLineWidth - aggregatedMetadata.FormattedQuery = cfg.Pretty(queryTree.AST) - + aggregatedMetadata.FormattedQuery = aggregatedMetadata.Query aggregatedMetadata.FingerprintID = string(tree.MustBeDString(row[3])) statement = serverpb.StatementDetailsResponse_CollectedStatementSummary{ diff --git a/pkg/sql/appstatspb/app_stats.proto b/pkg/sql/appstatspb/app_stats.proto index 0e57a4a9584d..3361c6a9fc72 100644 --- a/pkg/sql/appstatspb/app_stats.proto +++ b/pkg/sql/appstatspb/app_stats.proto @@ -226,9 +226,8 @@ message StatementStatisticsKey { message AggregatedStatementMetadata { optional string query = 1 [(gogoproto.nullable) = false]; - // Formatted query is the return of the key_data.query after prettify_statement. - // The query above cannot be replaced by the formatted value, because is used as is for - // diagnostic bundle. + // Formatted query is the same value of query. It used to be formatted with prettify_statement, + // but until that function is improved (#91197), it should not be used. optional string formatted_query = 2 [(gogoproto.nullable) = false]; optional string query_summary = 3 [(gogoproto.nullable) = false]; optional string stmt_type = 4 [(gogoproto.nullable) = false]; diff --git a/pkg/ui/workspaces/cluster-ui/src/api/txnInsightsApi.ts b/pkg/ui/workspaces/cluster-ui/src/api/txnInsightsApi.ts index 46ca3adecb3e..1e7b99a3c564 100644 --- a/pkg/ui/workspaces/cluster-ui/src/api/txnInsightsApi.ts +++ b/pkg/ui/workspaces/cluster-ui/src/api/txnInsightsApi.ts @@ -110,7 +110,7 @@ type FingerprintStmtsResponseColumns = { const fingerprintStmtsQuery = (stmtFingerprintIDs: string[]): string => ` SELECT DISTINCT ON (fingerprint_id) encode(fingerprint_id, 'hex') AS statement_fingerprint_id, - prettify_statement(metadata ->> 'query', 108, 1, 1) AS query + (metadata ->> 'query') AS query FROM crdb_internal.statement_statistics WHERE encode(fingerprint_id, 'hex') = ANY ARRAY[ ${stmtFingerprintIDs.map(id => `'${id}'`).join(",")} ]`; diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetails.tsx index 1e656f90b081..a90ff2251115 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetails.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/statementInsightDetails.tsx @@ -159,7 +159,11 @@ export const StatementInsightDetails: React.FC<
- +
diff --git a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsOverviewTab.tsx b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsOverviewTab.tsx index 9b15ee954e7b..cb74b65ecbd3 100644 --- a/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsOverviewTab.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/insights/workloadInsightDetails/transactionInsightDetailsOverviewTab.tsx @@ -131,7 +131,11 @@ the maximum number of statements was reached in the console.`; > - + {txnDetails && ( diff --git a/pkg/ui/workspaces/cluster-ui/src/jobs/jobDetailsPage/jobDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/jobs/jobDetailsPage/jobDetails.tsx index 9d827502dabc..72507998bb0f 100644 --- a/pkg/ui/workspaces/cluster-ui/src/jobs/jobDetailsPage/jobDetails.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/jobs/jobDetailsPage/jobDetails.tsx @@ -99,7 +99,11 @@ export class JobDetails extends React.Component { <> - + diff --git a/pkg/ui/workspaces/cluster-ui/src/sql/box.tsx b/pkg/ui/workspaces/cluster-ui/src/sql/box.tsx index 511f23f00ddf..10a923e84a1a 100644 --- a/pkg/ui/workspaces/cluster-ui/src/sql/box.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/sql/box.tsx @@ -14,6 +14,7 @@ import classNames from "classnames/bind"; import styles from "./sqlhighlight.module.scss"; import { api as clusterUiApi } from "../index"; +import { FormatQuery } from "src/util"; export enum SqlBoxSize { small = "small", @@ -26,6 +27,7 @@ export interface SqlBoxProps { zone?: clusterUiApi.DatabaseDetailsResponse; className?: string; size?: SqlBoxSize; + format?: boolean; } const cx = classNames.bind(styles); @@ -33,10 +35,13 @@ const cx = classNames.bind(styles); export class SqlBox extends React.Component { preNode: React.RefObject = React.createRef(); render(): React.ReactElement { + const value = this.props.format + ? FormatQuery(this.props.value) + : this.props.value; const sizeClass = this.props.size ? this.props.size : ""; return (
- +
); } diff --git a/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx index d4a27b9b7ee6..303acbac3143 100644 --- a/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/statementDetails/statementDetails.tsx @@ -501,6 +501,7 @@ export class StatementDetails extends React.Component<
@@ -684,6 +685,7 @@ export class StatementDetails extends React.Component< @@ -845,7 +847,11 @@ export class StatementDetails extends React.Component<
- +

diff --git a/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetails.tsx b/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetails.tsx index a5d5d23b0564..63eb25d3b9be 100644 --- a/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetails.tsx +++ b/pkg/ui/workspaces/cluster-ui/src/transactionDetails/transactionDetails.tsx @@ -338,6 +338,7 @@ export class TransactionDetails extends React.Component< @@ -458,6 +459,7 @@ export class TransactionDetails extends React.Component< diff --git a/pkg/ui/workspaces/cluster-ui/src/util/format.ts b/pkg/ui/workspaces/cluster-ui/src/util/format.ts index 8fcb4ec1d52c..a9c67ca6161f 100644 --- a/pkg/ui/workspaces/cluster-ui/src/util/format.ts +++ b/pkg/ui/workspaces/cluster-ui/src/util/format.ts @@ -352,3 +352,51 @@ export function EncodeDatabaseTableIndexUri( export function EncodeDatabaseUri(db: string): string { return `/database/${EncodeUriName(db)}`; } + +interface BreakLineReplacement { + [key: string]: string; +} + +const breakLinesKeywords: BreakLineReplacement = { + " FROM ": " FROM ", + " WHERE ": " WHERE ", + " AND ": " AND ", + " ORDER ": " ORDER ", + " LIMIT ": " LIMIT ", + " JOIN ": " JOIN ", + " ON ": " ON ", + " VALUES ": " VALUES ", +}; +const LINE_BREAK_LIMIT = 100; + +export function FormatQuery(query: string): string { + if (query == null) { + return ""; + } + Object.keys(breakLinesKeywords).forEach(key => { + query = query.replace(new RegExp(key, "g"), `\n${breakLinesKeywords[key]}`); + }); + const lines = query.split("\n").map(line => { + if (line.length <= LINE_BREAK_LIMIT) { + return line; + } + return breakLongLine(line, LINE_BREAK_LIMIT); + }); + + return lines.join("\n"); +} + +function breakLongLine(line: string, limit: number): string { + if (line.length <= limit) { + return line; + } + const idxComma = line.indexOf(",", limit); + if (idxComma == -1) { + return line; + } + + return `${line.substring(0, idxComma + 1)}\n${breakLongLine( + line.substring(idxComma + 1).trim(), + limit, + )}`; +}