From de9b7210c5a59de16a7b1ca6fb69141abf9d11f8 Mon Sep 17 00:00:00 2001 From: Mark Nguyen Date: Tue, 2 Jun 2026 17:21:25 -0700 Subject: [PATCH] Fix named parameters for function calls in postgres --- pegjs/postgresql.pegjs | 32 +++++++++++++++++++++++++++++++- test/postgres.spec.js | 14 ++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/pegjs/postgresql.pegjs b/pegjs/postgresql.pegjs index 7322b7020..98cf07b44 100644 --- a/pegjs/postgresql.pegjs +++ b/pegjs/postgresql.pegjs @@ -4393,6 +4393,36 @@ or_and_where_expr return result } +func_call_args + = head:func_call_arg tail:(__ (KW_AND / KW_OR / COMMA) __ func_call_arg)* { + // => binary_expr | { type: 'expr_list'; value: expr[] } + const len = tail.length + let result = head; + let seperator = '' + for (let i = 0; i < len; ++i) { + if (tail[i][1] === ',') { + seperator = ',' + if (!Array.isArray(result)) result = [result] + result.push(tail[i][3]) + } else { + result = createBinaryExpr(tail[i][1], result, tail[i][3]); + } + } + if (seperator === ',') { + const el = { type: 'expr_list' } + el.value = result + return el + } + return result + } + +func_call_arg + = name:ident_name __ s:(':=' / '=>') __ v:expr { + // => { type: 'func_arg'; value: { name: ident_name; symbol: string; expr: expr; } } + return { type: 'func_arg', value: { name, symbol: s, expr: v } } + } + / expr + or_expr = head:and_expr tail:(___ KW_OR __ and_expr)* { // => binary_expr @@ -5173,7 +5203,7 @@ func_call } return result } - / name:proc_func_name __ LPAREN __ l:or_and_where_expr? __ RPAREN { + / name:proc_func_name __ LPAREN __ l:func_call_args? __ RPAREN { // => { type: 'function'; name: proc_func_name; args: expr_list; } if (l && l.type !== 'expr_list') l = { type: 'expr_list', value: [l] } return { diff --git a/test/postgres.spec.js b/test/postgres.spec.js index b85da66ae..fe3800be8 100644 --- a/test/postgres.spec.js +++ b/test/postgres.spec.js @@ -2098,6 +2098,20 @@ describe('Postgres', () => { expect(getParsedSql(sql, opt)).to.equal(sql.slice(0, -1)) }) }) + describe('named function arguments', () => { + it('should support := named argument notation', () => { + const sql = 'SELECT * FROM sales.get_delivery_order_detail_v2(p_deal_id := NULL)' + expect(getParsedSql(sql, opt)).to.equal(sql) + }) + it('should support => named argument notation', () => { + const sql = 'SELECT * FROM sales.get_order(p_deal_id => 5)' + expect(getParsedSql(sql, opt)).to.equal(sql) + }) + it('should support mixed positional and named arguments', () => { + const sql = 'SELECT myfunc(1, b := 2, c => 3)' + expect(getParsedSql(sql, opt)).to.equal(sql) + }) + }) describe('tables to sql', () => { it('should parse object tables', () => { const ast = parser.astify(SQL_LIST[113].sql[0], opt)