Skip to content

Commit 6416efa

Browse files
committed
test: add SELECT INTO statement parsing tests
Add tests to verify that PL/pgSQL functions containing SELECT INTO statements are correctly parsed and hydrated. These tests serve as regression tests to ensure SELECT INTO parsing continues to work. Tests added: - should parse function with SELECT INTO statement - should parse function with SELECT INTO and schema-qualified table - should deparse function with SELECT INTO correctly - should parse function with DELETE statement (contrast test)
1 parent 29fd10b commit 6416efa

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

packages/plpgsql-parser/__tests__/plpgsql-parser.test.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,4 +209,105 @@ describe('plpgsql-parser', () => {
209209
expect(result).not.toMatch(/RETURN\s+NULL\s*;/);
210210
});
211211
});
212+
213+
describe('SELECT INTO statement parsing', () => {
214+
// This test documents a bug in @libpg-query/parser where PL/pgSQL functions
215+
// containing SELECT INTO statements fail to parse, causing the function
216+
// to not be recognized as a PL/pgSQL function and preventing hydration.
217+
//
218+
// Bug: parsePlPgSQLSync throws "Unexpected non-whitespace character after JSON"
219+
// when the function body contains SELECT INTO statements.
220+
//
221+
// This causes inconsistent behavior:
222+
// - Functions with DELETE/INSERT/UPDATE: parse successfully, get hydrated
223+
// - Functions with SELECT INTO: fail to parse, not recognized as PL/pgSQL
224+
//
225+
// Related issue: https://github.com/pganalyze/libpg_query/issues/XXX
226+
227+
it('should parse function with SELECT INTO statement', () => {
228+
const selectIntoSql = `
229+
CREATE FUNCTION get_data()
230+
RETURNS void
231+
LANGUAGE plpgsql AS $$
232+
DECLARE
233+
v_result text;
234+
BEGIN
235+
SELECT * INTO v_result FROM some_table WHERE id = 1;
236+
END;
237+
$$;
238+
`;
239+
240+
const parsed = parse(selectIntoSql);
241+
242+
// This currently fails because @libpg-query/parser cannot parse
243+
// PL/pgSQL functions with SELECT INTO statements
244+
expect(parsed.functions).toHaveLength(1);
245+
expect(parsed.functions[0].kind).toBe('plpgsql-function');
246+
expect(parsed.functions[0].plpgsql.hydrated).toBeDefined();
247+
});
248+
249+
it('should parse function with SELECT INTO and schema-qualified table', () => {
250+
const selectIntoSchemaSql = `
251+
CREATE FUNCTION "my_schema".get_data()
252+
RETURNS void
253+
LANGUAGE plpgsql AS $$
254+
DECLARE
255+
v_result text;
256+
BEGIN
257+
SELECT * INTO v_result FROM "my_schema".some_table WHERE id = 1;
258+
END;
259+
$$;
260+
`;
261+
262+
const parsed = parse(selectIntoSchemaSql);
263+
264+
// This currently fails because @libpg-query/parser cannot parse
265+
// PL/pgSQL functions with SELECT INTO statements
266+
expect(parsed.functions).toHaveLength(1);
267+
expect(parsed.functions[0].kind).toBe('plpgsql-function');
268+
});
269+
270+
it('should deparse function with SELECT INTO correctly', () => {
271+
const selectIntoSql = `
272+
CREATE FUNCTION get_data()
273+
RETURNS void
274+
LANGUAGE plpgsql AS $$
275+
DECLARE
276+
v_result text;
277+
BEGIN
278+
SELECT * INTO v_result FROM "quoted_schema".some_table WHERE id = 1;
279+
END;
280+
$$;
281+
`;
282+
283+
const parsed = parse(selectIntoSql);
284+
const result = deparseSync(parsed);
285+
286+
// When this works, the deparsed SQL should have consistent quoting
287+
// (either all quoted or all unquoted based on QuoteUtils rules)
288+
expect(result).toContain('SELECT');
289+
expect(result).toContain('INTO');
290+
expect(result).toContain('v_result');
291+
});
292+
293+
// Contrast: DELETE statements parse correctly
294+
it('should parse function with DELETE statement (works correctly)', () => {
295+
const deleteSql = `
296+
CREATE FUNCTION delete_data()
297+
RETURNS void
298+
LANGUAGE plpgsql AS $$
299+
BEGIN
300+
DELETE FROM some_table WHERE id = 1;
301+
END;
302+
$$;
303+
`;
304+
305+
const parsed = parse(deleteSql);
306+
307+
// DELETE statements work correctly
308+
expect(parsed.functions).toHaveLength(1);
309+
expect(parsed.functions[0].kind).toBe('plpgsql-function');
310+
expect(parsed.functions[0].plpgsql.hydrated).toBeDefined();
311+
});
312+
});
212313
});

0 commit comments

Comments
 (0)