MCPcopy Index your code
hub / github.com/bytebase/dbhub / explainQuery

Method explainQuery

src/connectors/sqlserver/index.ts:818–861  ·  view source on GitHub ↗

* Return the estimated execution plan for a query using SHOWPLAN_XML. * * SHOWPLAN_XML compiles the statement and returns its plan without executing * it, but it has two constraints: `SET SHOWPLAN_XML ON` must be the only * statement in its batch, and the setting is session scoped. The s

(innerQuery: string)

Source from the content-addressed store, hash-verified

816 * with SHOWPLAN enabled (which would return a plan instead of its results).
817 */
818 private async explainQuery(innerQuery: string): Promise<SQLResult> {
819 // Validate against comment/string-stripped SQL so comment-only input counts
820 // as empty and a SET SHOWPLAN can't hide behind comments.
821 const cleaned = stripCommentsAndStrings(innerQuery, "sqlserver").trim();
822 if (!cleaned) {
823 throw new Error("EXPLAIN requires a statement to analyze");
824 }
825
826 // Defense in depth: the SET SHOWPLAN session toggle is what makes EXPLAIN
827 // non-executing, so the explained statement must not disable it. SQL Server
828 // already rejects `SET SHOWPLAN_* OFF` alongside other statements in a
829 // batch, but enforcing it here keeps the read-only guarantee self-contained.
830 if (/\bset\s+showplan/i.test(cleaned)) {
831 throw new Error("EXPLAIN does not support SET SHOWPLAN statements");
832 }
833
834 if (!this.config) {
835 throw new Error("Not connected to SQL Server database");
836 }
837
838 const explainPool = new sql.ConnectionPool({
839 ...this.config,
840 pool: { ...this.config.pool, max: 1, min: 1 },
841 });
842
843 try {
844 await explainPool.connect();
845 // max:1 + sequential awaits guarantee both batches hit the same session.
846 await explainPool.request().batch("SET SHOWPLAN_XML ON");
847 const planResult = await explainPool.request().batch(innerQuery);
848
849 // The plan is returned as the single column of the first row.
850 const planRow = planResult.recordset?.[0];
851 const planXml = planRow ? Object.values(planRow)[0] : null;
852 return {
853 rows: planXml != null ? [{ plan: planXml }] : [],
854 rowCount: planXml != null ? 1 : 0,
855 };
856 } catch (error) {
857 throw new Error(`Failed to explain query: ${(error as Error).message}`);
858 } finally {
859 await explainPool.close();
860 }
861 }
862}
863
864// Create and register the connector

Callers 1

executeSQLMethod · 0.95

Calls 3

stripCommentsAndStringsFunction · 0.85
closeMethod · 0.80
connectMethod · 0.65

Tested by

no test coverage detected