@@ -557,3 +557,176 @@ test('return interval as string', async () => {
557
557
]
558
558
` )
559
559
} )
560
+
561
+ test ( 'line position error' , async ( ) => {
562
+ const res = await app . inject ( {
563
+ method : 'POST' ,
564
+ path : '/query' ,
565
+ payload : { query : 'SELECT *\nFROM pg_class\nWHERE relname = missing_quotes;' } ,
566
+ } )
567
+ expect ( res . json ( ) ) . toMatchInlineSnapshot ( `
568
+ {
569
+ "code": "42703",
570
+ "error": "ERROR: 42703: column "missing_quotes" does not exist
571
+ LINE 3: WHERE relname = missing_quotes;
572
+ ^
573
+ ",
574
+ "file": "parse_relation.c",
575
+ "formattedError": "ERROR: 42703: column "missing_quotes" does not exist
576
+ LINE 3: WHERE relname = missing_quotes;
577
+ ^
578
+ ",
579
+ "length": 114,
580
+ "line": "3589",
581
+ "message": "column "missing_quotes" does not exist",
582
+ "name": "error",
583
+ "position": "40",
584
+ "routine": "errorMissingColumn",
585
+ "severity": "ERROR",
586
+ }
587
+ ` )
588
+ } )
589
+
590
+ test ( 'error with additional details' , async ( ) => {
591
+ // This query will generate an error with details
592
+ const res = await app . inject ( {
593
+ method : 'POST' ,
594
+ path : '/query' ,
595
+ payload : {
596
+ query : `DO $$
597
+ DECLARE
598
+ my_var int;
599
+ BEGIN
600
+ -- This will trigger an error with detail, hint, and context
601
+ SELECT * INTO STRICT my_var FROM (VALUES (1), (2)) AS t(v);
602
+ END $$;` ,
603
+ } ,
604
+ } )
605
+
606
+ expect ( res . json ( ) ) . toMatchInlineSnapshot ( `
607
+ {
608
+ "code": "P0003",
609
+ "error": "ERROR: P0003: query returned more than one row
610
+ HINT: Make sure the query returns a single row, or use LIMIT 1.
611
+ CONTEXT: PL/pgSQL function inline_code_block line 6 at SQL statement
612
+ ",
613
+ "file": "pl_exec.c",
614
+ "formattedError": "ERROR: P0003: query returned more than one row
615
+ HINT: Make sure the query returns a single row, or use LIMIT 1.
616
+ CONTEXT: PL/pgSQL function inline_code_block line 6 at SQL statement
617
+ ",
618
+ "hint": "Make sure the query returns a single row, or use LIMIT 1.",
619
+ "length": 216,
620
+ "line": "4349",
621
+ "message": "query returned more than one row",
622
+ "name": "error",
623
+ "routine": "exec_stmt_execsql",
624
+ "severity": "ERROR",
625
+ "where": "PL/pgSQL function inline_code_block line 6 at SQL statement",
626
+ }
627
+ ` )
628
+ } )
629
+
630
+ test ( 'error with all formatting properties' , async ( ) => {
631
+ // This query will generate an error with all formatting properties
632
+ const res = await app . inject ( {
633
+ method : 'POST' ,
634
+ path : '/query' ,
635
+ payload : {
636
+ query : `
637
+ DO $$
638
+ BEGIN
639
+ -- Using EXECUTE to force internal query to appear
640
+ EXECUTE 'SELECT * FROM nonexistent_table WHERE id = 1';
641
+ EXCEPTION WHEN OTHERS THEN
642
+ -- Re-raise with added context
643
+ RAISE EXCEPTION USING
644
+ ERRCODE = SQLSTATE,
645
+ MESSAGE = SQLERRM,
646
+ DETAIL = 'This is additional detail information',
647
+ HINT = 'This is a hint for fixing the issue',
648
+ SCHEMA = 'public';
649
+ END $$;
650
+ ` ,
651
+ } ,
652
+ } )
653
+
654
+ expect ( res . json ( ) ) . toMatchInlineSnapshot ( `
655
+ {
656
+ "code": "42P01",
657
+ "detail": "This is additional detail information",
658
+ "error": "ERROR: 42P01: relation "nonexistent_table" does not exist
659
+ DETAIL: This is additional detail information
660
+ HINT: This is a hint for fixing the issue
661
+ CONTEXT: PL/pgSQL function inline_code_block line 7 at RAISE
662
+ ",
663
+ "file": "pl_exec.c",
664
+ "formattedError": "ERROR: 42P01: relation "nonexistent_table" does not exist
665
+ DETAIL: This is additional detail information
666
+ HINT: This is a hint for fixing the issue
667
+ CONTEXT: PL/pgSQL function inline_code_block line 7 at RAISE
668
+ ",
669
+ "hint": "This is a hint for fixing the issue",
670
+ "length": 242,
671
+ "line": "3859",
672
+ "message": "relation "nonexistent_table" does not exist",
673
+ "name": "error",
674
+ "routine": "exec_stmt_raise",
675
+ "schema": "public",
676
+ "severity": "ERROR",
677
+ "where": "PL/pgSQL function inline_code_block line 7 at RAISE",
678
+ }
679
+ ` )
680
+ } )
681
+
682
+ test ( 'error with internalQuery property' , async ( ) => {
683
+ // First create a function that will execute a query internally
684
+ await app . inject ( {
685
+ method : 'POST' ,
686
+ path : '/query' ,
687
+ payload : {
688
+ query : `
689
+ CREATE OR REPLACE FUNCTION test_internal_query() RETURNS void AS $$
690
+ BEGIN
691
+ -- This query will be the "internal query" when it fails
692
+ EXECUTE 'SELECT * FROM nonexistent_table';
693
+ RETURN;
694
+ END;
695
+ $$ LANGUAGE plpgsql;
696
+ ` ,
697
+ } ,
698
+ } )
699
+
700
+ // Now call the function to trigger the error with internalQuery
701
+ const res = await app . inject ( {
702
+ method : 'POST' ,
703
+ path : '/query' ,
704
+ payload : {
705
+ query : 'SELECT test_internal_query();' ,
706
+ } ,
707
+ } )
708
+
709
+ expect ( res . json ( ) ) . toMatchInlineSnapshot ( `
710
+ {
711
+ "code": "42P01",
712
+ "error": "ERROR: 42P01: relation "nonexistent_table" does not exist
713
+ QUERY: SELECT * FROM nonexistent_table
714
+ CONTEXT: PL/pgSQL function test_internal_query() line 4 at EXECUTE
715
+ ",
716
+ "file": "parse_relation.c",
717
+ "formattedError": "ERROR: 42P01: relation "nonexistent_table" does not exist
718
+ QUERY: SELECT * FROM nonexistent_table
719
+ CONTEXT: PL/pgSQL function test_internal_query() line 4 at EXECUTE
720
+ ",
721
+ "internalPosition": "15",
722
+ "internalQuery": "SELECT * FROM nonexistent_table",
723
+ "length": 208,
724
+ "line": "1381",
725
+ "message": "relation "nonexistent_table" does not exist",
726
+ "name": "error",
727
+ "routine": "parserOpenTable",
728
+ "severity": "ERROR",
729
+ "where": "PL/pgSQL function test_internal_query() line 4 at EXECUTE",
730
+ }
731
+ ` )
732
+ } )
0 commit comments