Skip to content

Commit

Permalink
refactor: support quoted function name, quoted schema name in pg
Browse files Browse the repository at this point in the history
  • Loading branch information
taozhi8833998 committed Feb 9, 2024
1 parent f397135 commit 8e98fb9
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 27 deletions.
46 changes: 27 additions & 19 deletions pegjs/postgresql.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ create_func_opt
return {
prefix: 'support',
type: 'default',
value: n
value: [n.schema && n.schema.value, n.name.value].filter(v => v).join('.')
}
}
/ KW_SET __ ca:ident_name __ e:((('TO'i / '=') __ ident_list) / (KW_FROM __ 'CURRENT'i))? __ {
Expand Down Expand Up @@ -4065,6 +4065,13 @@ column_list
return createList(head, tail);
}

ident_without_kw_type
= n:ident_name {
// => { type: 'default', value: string }
return { type: 'default', value: n }
}
/ quoted_ident_type

ident_type
= name:ident_name !{ return reservedMap[name.toUpperCase()] === true; } {
// => ident_name
Expand Down Expand Up @@ -4138,13 +4145,13 @@ column_without_kw

column_without_kw_type
= n:column_name {
// => { type: 'origin', value: string }
// => { type: 'default', value: string }
return { type: 'default', value: n }
}
/ quoted_ident_type
column_type
= name:column_name !{ return reservedMap[name.toUpperCase()] === true; } {
// => { type: 'origin', value: string }
// => { type: 'default', value: string }
return { type: 'default', value: name }
}
/ quoted_ident_type
Expand Down Expand Up @@ -4399,22 +4406,22 @@ trim_rem

trim_func_clause
= 'trim'i __ LPAREN __ tr:trim_rem? __ s:expr __ RPAREN {
// => { type: 'function'; name: string; args: expr_list; }
// => { type: 'function'; name: proc_func_name; args: expr_list; }
let args = tr || { type: 'expr_list', value: [] }
args.value.push(s)
return {
type: 'function',
name: 'TRIM',
name: { name: { type: 'origin', value: 'trim' }},
args,
};
}

tablefunc_clause
= 'crosstab'i __ LPAREN __ s:expr_list __ RPAREN __ KW_AS __ n:ident_name __ LPAREN __ cds:column_data_type_list __ RPAREN {
// => { type: 'tablefunc'; name: crosstab; args: expr_list; as: func_call }
// => { type: 'tablefunc'; name: proc_func_name; args: expr_list; as: func_call }
return {
type: 'tablefunc',
name: 'crosstab',
name: { name: { type: 'default', value: 'crosstab' } } ,
args: s,
as: {
type: 'function',
Expand All @@ -4427,35 +4434,35 @@ tablefunc_clause
func_call
= trim_func_clause / tablefunc_clause
/ name:'now'i __ LPAREN __ l:expr_list? __ RPAREN __ 'at'i __ KW_TIME __ 'zone'i __ z:literal_string {
// => { type: 'function'; name: string; args: expr_list; suffix: literal_string; }
// => { type: 'function'; name: proc_func_name; args: expr_list; suffix: literal_string; }
z.prefix = 'at time zone'
return {
type: 'function',
name: name,
name: { name: { type: 'default', value: name } },
args: l ? l: { type: 'expr_list', value: [] },
suffix: z
};
}
/ name:scalar_func __ LPAREN __ l:expr_list? __ RPAREN __ bc:over_partition? {
// => { type: 'function'; name: string; args: expr_list; over?: over_partition; }
// => { type: 'function'; name: proc_func_name; args: expr_list; over?: over_partition; }
return {
type: 'function',
name: name,
name: { name: { type: 'origin', value: name } },
args: l ? l: { type: 'expr_list', value: [] },
over: bc
};
}
/ extract_func
/ f:scalar_time_func __ up:on_update_current_timestamp? {
// => { type: 'function'; name: string; over?: on_update_current_timestamp; }
// => { type: 'function'; name: proc_func_name; over?: on_update_current_timestamp; }
return {
type: 'function',
name: f,
name: { name: { type: 'origin', value: f } },
over: up
}
}
/ name:proc_func_name __ LPAREN __ l:or_and_where_expr? __ RPAREN {
// => { type: 'function'; name: string; args: expr_list; }
// => { type: 'function'; name: proc_func_name; args: expr_list; }
if (l && l.type !== 'expr_list') l = { type: 'expr_list', value: [l] }
return {
type: 'function',
Expand Down Expand Up @@ -5169,13 +5176,14 @@ proc_primary
}

proc_func_name
= dt:ident_name tail:(__ DOT __ ident_name)? {
// => string
let name = dt
= dt:ident_without_kw_type tail:(__ DOT __ ident_without_kw_type)? {
// => { schema?: ident_without_kw_type, name: ident_without_kw_type }
const result = { name: dt }
if (tail !== null) {
name = `${dt}.${tail[3]}`
result.schema = dt
result.name = tail[3]
}
return name;
return result
}

proc_func_call
Expand Down
10 changes: 6 additions & 4 deletions src/func.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,11 @@ function funcToSQL(expr) {
const collateStr = commonTypeValue(collate).join(' ')
const overStr = overToSQL(over)
const suffixStr = exprToSQL(suffix)
if (!args) return [name, overStr].filter(hasVal).join(' ')
const funcName = typeof name === 'string' ? name : [name.schema, name.name].map(literalToSQL).filter(hasVal).join('.')
if (!args) return [funcName, overStr].filter(hasVal).join(' ')
let separator = expr.separator || ', '
if (toUpper(name) === 'TRIM') separator = ' '
let str = [name]
if (toUpper(funcName) === 'TRIM') separator = ' '
let str = [funcName]
str.push(args_parentheses === false ? ' ' : '(')
str.push(exprToSQL(args).join(separator))
if (args_parentheses !== false) str.push(')')
Expand All @@ -84,7 +85,8 @@ function funcToSQL(expr) {

function tablefuncFunToSQL(expr) {
const { as, name, args } = expr
const result = [`${name}(${exprToSQL(args).join(', ')})`, 'AS', funcToSQL(as)]
const funcName = typeof name === 'string' ? name : [name.schema, name.name].map(literalToSQL).filter(hasVal).join('.')
const result = [`${funcName}(${exprToSQL(args).join(', ')})`, 'AS', funcToSQL(as)]
return result.join(' ')
}

Expand Down
18 changes: 14 additions & 4 deletions test/postgres.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1408,11 +1408,21 @@ describe('Postgres', () => {
'SELECT "abc", def FROM "tableName"'
]
},
{
title: 'quoted function name',
sql: [
'SELECT * FROM "func"("start_time", "end_time")',
'SELECT * FROM "func"("start_time", "end_time")'
]
},
{
title: 'function name prefixed with quoted schema',
sql: [
'SELECT * FROM "schema"."func"("start_time", "end_time")',
'SELECT * FROM "schema"."func"("start_time", "end_time")'
]
},
]
// it.only('ttttt', () => {
// const sql = 'select "abc", def from tableName'
// expect(getParsedSql(sql, opt)).to.equal('SELECT "abc", def FROM "tableName"')
// })
function neatlyNestTestedSQL(sqlList){
sqlList.forEach(sqlInfo => {
const {title, sql} = sqlInfo
Expand Down

0 comments on commit 8e98fb9

Please sign in to comment.