diff --git a/apps/desktop/src/lib/__tests__/sql/sqlStatementRanges.spec.ts b/apps/desktop/src/lib/__tests__/sql/sqlStatementRanges.spec.ts index 1d69593f6c..09a48ecb8b 100644 --- a/apps/desktop/src/lib/__tests__/sql/sqlStatementRanges.spec.ts +++ b/apps/desktop/src/lib/__tests__/sql/sqlStatementRanges.spec.ts @@ -91,6 +91,22 @@ BEGIN END; SELECT 2;`; +const mysqlDelimitedRoutineFixture = `DELIMITER // +CREATE PROCEDURE sp_insert_random_users(IN p_count INT) +BEGIN + DECLARE i INT DEFAULT 0; + DECLARE v_name VARCHAR(32); + + WHILE i < p_count DO + SET v_name = CONCAT('user_', i); + INSERT INTO t_user (username) VALUES (v_name); + SET i = i + 1; + END WHILE; +END // +DELIMITER ; + +CALL sp_insert_random_users(100);`; + const sapHanaDoBlockFixture = `DO BEGIN SELECT 1 AS "Result" FROM DUMMY; @@ -547,6 +563,10 @@ describe("executableStatementRanges", () => { expect(rangeSqlTexts(executableStatementRanges(mysqlRoutineWithLoopsFixture, "mysql"))).toEqual([mysqlRoutineWithLoopsFixture.slice(0, mysqlRoutineWithLoopsFixture.indexOf("\nSELECT 2;")).replace(/;$/, "").trim(), "SELECT 2"]); }); + it("does not expose run targets for statements inside a delimited MySQL routine", () => { + expect(rangeSqlTexts(executableStatementRanges(mysqlDelimitedRoutineFixture, "mysql"))).toEqual([mysqlDelimitedRoutineFixture.slice(mysqlDelimitedRoutineFixture.indexOf("CREATE PROCEDURE"), mysqlDelimitedRoutineFixture.indexOf(" //\nDELIMITER")), "CALL sp_insert_random_users(100)"]); + }); + it("does not split executable SAP HANA DO ranges at inner statements", () => { expect(rangeSqlTexts(executableStatementRanges(sapHanaDoBlockFixture, "saphana"))).toEqual([sapHanaDoBlockFixture.slice(0, sapHanaDoBlockFixture.indexOf("\nSELECT 2")), "SELECT 2 FROM DUMMY"]); }); diff --git a/apps/desktop/src/lib/sql/sqlStatementRanges.ts b/apps/desktop/src/lib/sql/sqlStatementRanges.ts index e4c8377cc8..3caa1375c4 100644 --- a/apps/desktop/src/lib/sql/sqlStatementRanges.ts +++ b/apps/desktop/src/lib/sql/sqlStatementRanges.ts @@ -469,6 +469,8 @@ function rangeForCursorInSoftRanges(sql: string, ranges: RawStatement[], pos: nu function splitStatementRangeAtSoftStarts(sql: string, statement: RawStatement, databaseType?: DatabaseType): RawStatement[] { if (isOraclePlSqlStatement(statement.sql, databaseType)) return [statement]; if (isSapHanaScriptBlockStatement(statement.sql, databaseType)) return [statement]; + // Routine bodies contain top-level-looking SET/INSERT/SELECT lines that are not independent statements. + if (isMysqlRoutineBlockDatabase(databaseType) && startsWithMysqlRoutineBlock(statement.sql)) return [statement]; const lineStarts = topLevelSoftStatementLineStarts(sql, statement, databaseType); if (lineStarts.length <= 1) return [statement];