@@ -142,14 +142,23 @@ func isDOBlock(stmt *parser.Statement) bool {
142142// instrumentPlpgsqlFunction instruments a PL/pgSQL function with line-by-line coverage
143143// Uses pg_query.ParsePlPgSqlToJSON to properly parse the PL/pgSQL AST
144144func instrumentPlpgsqlFunction (stmt * parser.Statement , filePath string ) (string , []CoveragePoint ) {
145- // Trim leading empty lines from stmt.RawSQL to ensure PL/pgSQL parser line numbers match
146145 lines := strings .Split (stmt .RawSQL , "\n " )
146+
147+ // Trim leading comments and empty lines from stmt.RawSQL to ensure PL/pgSQL parser line numbers match
148+ // We need to find the line that starts with CREATE FUNCTION/PROCEDURE or DO
147149 firstNonEmptyIndex := 0
148150 for i , line := range lines {
149- if len (strings .TrimSpace (line )) > 0 {
151+ trimmed := strings .TrimSpace (line )
152+ // Look for CREATE FUNCTION, CREATE PROCEDURE, or DO
153+ if strings .HasPrefix (strings .ToUpper (trimmed ), "CREATE" ) ||
154+ strings .HasPrefix (strings .ToUpper (trimmed ), "DO" ) {
150155 firstNonEmptyIndex = i
151156 break
152157 }
158+ // If not found yet, at least skip empty lines
159+ if trimmed != "" && firstNonEmptyIndex == 0 {
160+ firstNonEmptyIndex = i
161+ }
153162 }
154163
155164 trimmedSQL := strings .Join (lines [firstNonEmptyIndex :], "\n " )
@@ -416,13 +425,12 @@ func injectNotifyAtLines(stmt *parser.Statement, filePath string, executableLine
416425 lines := strings .Split (stmt .RawSQL , "\n " )
417426 result := strings.Builder {}
418427
419- // The line numbers from ParsePlPgSqlToJSON map directly to 0-based indices in stmt.RawSQL
420- // (i.e., PL/pgSQL line N → index N in lines array)
421- // To get file line numbers: PL/pgSQL line N → stmt.RawSQL index N → file line (stmt.StartLine + N)
428+ // The line numbers from ParsePlPgSqlToJSON are 0-based indices relative to the trimmed SQL string
429+ // To get file line numbers: PL/pgSQL line N (0-based) → stmt.RawSQL index N → file line (stmt.StartLine + N)
422430
423431 absoluteLines := make (map [int ]bool )
424432 for _ , plpgsqlLine := range executableLines {
425- // plpgsqlLine maps to index plpgsqlLine in the lines array (0-based)
433+ // plpgsqlLine is a 0-based index from PL/pgSQL parser
426434 lineIndex := plpgsqlLine
427435 if lineIndex >= 0 && lineIndex < len (lines ) {
428436 // Convert to absolute file line number (1-based)
0 commit comments