From 223b74e9231c48c0f58d641d762d4f56ccafc98d Mon Sep 17 00:00:00 2001 From: taozhi8833998 Date: Wed, 9 Oct 2024 10:09:01 +0800 Subject: [PATCH] refactor: add schema and server name in tableList --- README.md | 3 +++ pegjs/flinksql.pegjs | 34 ++++++++++++++++++---------------- pegjs/noql.pegjs | 33 ++++++++++++++++++--------------- pegjs/postgresql.pegjs | 35 +++++++++++++++++++---------------- pegjs/redshift.pegjs | 33 ++++++++++++++++++--------------- pegjs/snowflake.pegjs | 34 ++++++++++++++++++---------------- pegjs/transactsql.pegjs | 37 ++++++++++++++++++++----------------- pegjs/trino.pegjs | 34 ++++++++++++++++++---------------- test/snowflake.spec.js | 21 +++++++++++++++++++++ 9 files changed, 153 insertions(+), 111 deletions(-) diff --git a/README.md b/README.md index cb13cf72..235b1951 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,9 @@ const tableList = parser.tableList('SELECT * FROM t', opt); console.log(tableList); // ["select::null::t"] ``` +- if the table name is prefixed with database name, the table name will be parsed as **dbName::tableName** +- if the table name is prefixed with database and schema name, the table name will be parsed as **dbName.schemaName::tableName** +- if the table name is prefixed with server name in TransactSQL, the table name will be parsed as **serverName.dbName.schemaName::tableName** ### Get the SQL visited columns diff --git a/pegjs/flinksql.pegjs b/pegjs/flinksql.pegjs index 5bcde05b..19d396b0 100644 --- a/pegjs/flinksql.pegjs +++ b/pegjs/flinksql.pegjs @@ -667,7 +667,7 @@ create_table_stmt ir: (KW_IGNORE / KW_REPLACE)? __ as: KW_AS? __ qe: union_stmt? { - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -693,7 +693,7 @@ create_table_stmt t:table_ref_list __ wr:(KW_WITH __ LPAREN __ with_table_options __ RPAREN)? __ lt:create_like_table { - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -934,7 +934,7 @@ drop_stmt = a:KW_DROP __ r:KW_TABLE __ t:table_ref_list { - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -975,7 +975,7 @@ truncate_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1021,7 +1021,7 @@ alter_table_stmt } => AstStatement */ - if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${table.db}::${table.table}`)); + if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${[table.db, table.schema].filter(Boolean).join('.') || null}::${table.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1518,7 +1518,7 @@ rename_stmt } => AstStatement */ - t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${dt.db}::${dt.table}`))) + t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${[dt.db, dt.schema].filter(Boolean).join('.') || null}::${dt.table}`))) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1580,7 +1580,7 @@ lock_stmt => AstStatement */ - if (t) t.forEach(tt => tableList.add(`lock::${tt.db}::${tt.table}`)) + if (t) t.forEach(tt => tableList.add(`lock::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1677,7 +1677,7 @@ select_stmt_nake orderby?: order_by_clause; limit?: limit_clause; }*/ - if(f) f.forEach(info => info.table && tableList.add(`select::${info.db}::${info.table}`)); + if(f) f.forEach(info => info.table && tableList.add(`select::${[info.db, info.schema].filter(Boolean).join('.') || null}::${info.table}`)); return { with: cte, type: 'select', @@ -1955,7 +1955,6 @@ table_name } / dt:ident __ DOT __ STAR { // => IGNORE - tableList.add(`select::${dt}::(.*)`); return { db: dt, table: '*' @@ -2060,10 +2059,11 @@ update_stmt */ const dbObj = {} if (t) t.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { db, as, schema, table, join } = tableInfo const action = join ? 'select' : 'update' - if (db) dbObj[table] = db - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [db, schema].filter(Boolean).join('.') || null + if (db) dbObj[table] = fullName + if (table) tableList.add(`${action}::${fullName}::${table}`) }); if(l) { l.forEach(col => { @@ -2105,15 +2105,17 @@ delete_stmt => AstStatement */ if(f) f.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { db, schema, as, table, join } = tableInfo const action = join ? 'select' : 'delete' - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [db, schema].filter(Boolean).join('.') || null + if (table) tableList.add(`${action}::${fullName}::${table}`) if (!join) columnList.add(`delete::${table}::(.*)`); }); if (t === null && f.length === 1) { const tableInfo = f[0] t = [{ db: tableInfo.db, + schema: tableInfo.schema, table: tableInfo.table, as: tableInfo.as, addition: true @@ -2192,7 +2194,7 @@ replace_insert_stmt => AstStatement */ if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) t.as = null } if (c) { @@ -2230,7 +2232,7 @@ insert_no_columns_stmt r:returning_stmt? { // => AstStatement if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) columnList.add(`insert::${t.table}::(.*)`); t.as = null } diff --git a/pegjs/noql.pegjs b/pegjs/noql.pegjs index fd98953e..4153f7f6 100644 --- a/pegjs/noql.pegjs +++ b/pegjs/noql.pegjs @@ -798,7 +798,7 @@ create_table_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -829,7 +829,7 @@ create_table_stmt } => AstStatement; */ - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1290,7 +1290,7 @@ drop_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1342,7 +1342,7 @@ truncate_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1526,7 +1526,7 @@ alter_table_stmt } => AstStatement */ - if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${table.db}::${table.table}`)); + if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${[table.db, table.schema].filter(Boolean).join('.') || null}::${table.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -2124,7 +2124,7 @@ rename_stmt } => AstStatement */ - t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${dt.db}::${dt.table}`))) + t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${[dt.db, dt.schema].filter(Boolean).join('.') || null}::${dt.table}`))) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -2179,7 +2179,7 @@ lock_stmt => AstStatement */ - if (t) t.forEach(tt => tableList.add(`lock::${tt.db}::${tt.table}`)) + if (t) t.forEach(tt => tableList.add(`lock::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -2737,7 +2737,7 @@ select_stmt_nake if ((ci && fi) || (ci && li) || (fi && li) || (ci && fi && li)) { throw new Error('A given SQL statement can contain at most one INTO clause') } - if(f) f.forEach(info => info.table && tableList.add(`select::${info.db}::${info.table}`)); + if(f) f.forEach(info => info.table && tableList.add(`select::${[info.db, info.schema].filter(Boolean).join('.') || null}::${info.table}`)); return { with: cte, type: 'select', @@ -3318,10 +3318,11 @@ update_stmt */ const dbObj = {} if (t) t.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { db, as, schema, table, join } = tableInfo const action = join ? 'select' : 'update' - if (db) dbObj[table] = db - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [db, schema].filter(Boolean).join('.') || null + if (db) dbObj[table] = fullName + if (table) tableList.add(`${action}::${fullName}::${table}`) }); if(l) { l.forEach(col => { @@ -3365,15 +3366,17 @@ delete_stmt => AstStatement */ if(f) f.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { db, as, schema, table, join } = tableInfo const action = join ? 'select' : 'delete' - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [db, schema].filter(Boolean).join('.') || null + if (table) tableList.add(`${action}::${fullName}::${table}`) if (!join) columnList.add(`delete::${table}::(.*)`); }); if (t === null && f.length === 1) { const tableInfo = f[0] t = [{ db: tableInfo.db, + schema: tableInfo.schema, table: tableInfo.table, as: tableInfo.as, addition: true @@ -3499,7 +3502,7 @@ replace_insert_stmt => AstStatement */ if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) t.as = null } if (c) { @@ -3538,7 +3541,7 @@ insert_no_columns_stmt r:returning_stmt? { // => AstStatement if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) columnList.add(`insert::${t.table}::(.*)`); t.as = null } diff --git a/pegjs/postgresql.pegjs b/pegjs/postgresql.pegjs index 7fe8d197..d1682976 100644 --- a/pegjs/postgresql.pegjs +++ b/pegjs/postgresql.pegjs @@ -815,7 +815,7 @@ create_table_stmt t:table_ref_list __ po:create_table_partition_of { // => AstStatement - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -857,7 +857,7 @@ create_table_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -888,7 +888,7 @@ create_table_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1444,7 +1444,7 @@ drop_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1488,7 +1488,7 @@ drop_stmt truncate_table_name = t:table_name __ s:STAR? { // => table_name & { suffix?: string } - tableList.add(`truncate::${t.db}::${t.table}`) + tableList.add(`truncate::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) if (s) t.suffix = s return t } @@ -1704,7 +1704,7 @@ alter_table_stmt } => AstStatement */ - if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${table.db}::${table.table}`)); + if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${[table.db, table.schema].filter(Boolean).join('.') || null}::${table.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -2424,7 +2424,7 @@ rename_stmt } => AstStatement */ - t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${dt.db}::${dt.table}`))) + t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${[dt.db, dt.schema].filter(Boolean).join('.') || null}::${dt.table}`))) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -2486,7 +2486,7 @@ lock_stmt => AstStatement */ - if (t) t.forEach(tt => tableList.add(`lock::${tt.db}::${tt.table}`)) + if (t) t.forEach(tt => tableList.add(`lock::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -3195,7 +3195,7 @@ select_stmt_nake if ((ci && fi) || (ci && li) || (fi && li) || (ci && fi && li)) { throw new Error('A given SQL statement can contain at most one INTO clause') } - if(f) f.forEach(info => info.table && tableList.add(`select::${info.db}::${info.table}`)); + if(f) f.forEach(info => info.table && tableList.add(`select::${[info.db, info.schema].filter(Boolean).join('.') || null}::${info.table}`)); return { with: cte, type: 'select', @@ -3809,10 +3809,11 @@ update_stmt */ const dbObj = {} if (t) t.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { db, schema, as, table, join } = tableInfo const action = join ? 'select' : 'update' - if (db) dbObj[table] = db - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [db, schema].filter(Boolean).join('.') || null + if (db) dbObj[table] = fullName + if (table) tableList.add(`${action}::${fullName}::${table}`) }); if(l) { l.forEach(col => { @@ -3856,15 +3857,17 @@ delete_stmt => AstStatement */ if(f) f.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { db, as, schema, table, join } = tableInfo const action = join ? 'select' : 'delete' - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [db, schema].filter(Boolean).join('.') || null + if (table) tableList.add(`${action}::${fullName}::${table}`) if (!join) columnList.add(`delete::${table}::(.*)`); }); if (t === null && f.length === 1) { const tableInfo = f[0] t = [{ db: tableInfo.db, + schema: tableInfo.schema, table: tableInfo.table, as: tableInfo.as, addition: true @@ -3990,7 +3993,7 @@ replace_insert_stmt => AstStatement */ if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) t.as = null } if (c) { @@ -4029,7 +4032,7 @@ insert_no_columns_stmt r:returning_stmt? { // => AstStatement if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) columnList.add(`insert::${t.table}::(.*)`); t.as = null } diff --git a/pegjs/redshift.pegjs b/pegjs/redshift.pegjs index 944c1ff2..95272144 100644 --- a/pegjs/redshift.pegjs +++ b/pegjs/redshift.pegjs @@ -809,7 +809,7 @@ create_table_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -840,7 +840,7 @@ create_table_stmt } => AstStatement; */ - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1301,7 +1301,7 @@ drop_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1353,7 +1353,7 @@ truncate_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1537,7 +1537,7 @@ alter_table_stmt } => AstStatement */ - if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${table.db}::${table.table}`)); + if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${[table.db, table.schema].filter(Boolean).join('.') || null}::${table.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -2140,7 +2140,7 @@ rename_stmt } => AstStatement */ - t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${dt.db}::${dt.table}`))) + t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${[dt.db, dt.schema].filter(Boolean).join('.') || null}::${dt.table}`))) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -2195,7 +2195,7 @@ lock_stmt => AstStatement */ - if (t) t.forEach(tt => tableList.add(`lock::${tt.db}::${tt.table}`)) + if (t) t.forEach(tt => tableList.add(`lock::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -2767,7 +2767,7 @@ select_stmt_nake if ((ci && fi) || (ci && li) || (fi && li) || (ci && fi && li)) { throw new Error('A given SQL statement can contain at most one INTO clause') } - if(f) f.forEach(info => info.table && tableList.add(`select::${info.db}::${info.table}`)); + if(f) f.forEach(info => info.table && tableList.add(`select::${[info.db, info.schema].filter(Boolean).join('.') || null}::${info.table}`)); return { with: cte, type: 'select', @@ -3347,10 +3347,11 @@ update_stmt */ const dbObj = {} if (t) t.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { db, as, schema, table, join } = tableInfo const action = join ? 'select' : 'update' - if (db) dbObj[table] = db - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [db, schema].filter(Boolean).join('.') || null + if (db) dbObj[table] = fullName + if (table) tableList.add(`${action}::${fullName}::${table}`) }); if(l) { l.forEach(col => { @@ -3394,15 +3395,17 @@ delete_stmt => AstStatement */ if(f) f.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { db, as, schema, table, join } = tableInfo const action = join ? 'select' : 'delete' - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [db, schema].filter(Boolean).join('.') || null + if (table) tableList.add(`${action}::${fullName}::${table}`) if (!join) columnList.add(`delete::${table}::(.*)`); }); if (t === null && f.length === 1) { const tableInfo = f[0] t = [{ db: tableInfo.db, + schema: tableInfo.schema, table: tableInfo.table, as: tableInfo.as, addition: true @@ -3528,7 +3531,7 @@ replace_insert_stmt => AstStatement */ if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) t.as = null } if (c) { @@ -3567,7 +3570,7 @@ insert_no_columns_stmt r:returning_stmt? { // => AstStatement if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) columnList.add(`insert::${t.table}::(.*)`); t.as = null } diff --git a/pegjs/snowflake.pegjs b/pegjs/snowflake.pegjs index 918edffb..466c3e6b 100644 --- a/pegjs/snowflake.pegjs +++ b/pegjs/snowflake.pegjs @@ -525,7 +525,7 @@ create_table_stmt ir:(KW_IGNORE / KW_REPLACE)? __ as:KW_AS? __ qe:union_stmt? { - tableList.add(`create::${t.db}::${t.table}`) + tableList.add(`create::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -559,7 +559,7 @@ create_table_stmt } => AstStatement; */ - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1014,7 +1014,7 @@ drop_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1066,7 +1066,7 @@ truncate_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1250,7 +1250,7 @@ alter_table_stmt } => AstStatement */ - if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${table.db}::${table.table}`)); + if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${[table.db, table.schema].filter(Boolean).join('.') || null}::${table.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1848,7 +1848,7 @@ rename_stmt } => AstStatement */ - t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${dt.db}::${dt.table}`))) + t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${[dt.db, dt.schema].filter(Boolean).join('.') || null}::${dt.table}`))) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1903,7 +1903,7 @@ lock_stmt => AstStatement */ - if (t) t.forEach(tt => tableList.add(`lock::${tt.db}::${tt.table}`)) + if (t) t.forEach(tt => tableList.add(`lock::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -2088,7 +2088,7 @@ select_stmt_nake if ((ci && fi) || (ci && li) || (fi && li) || (ci && fi && li)) { throw new Error('A given SQL statement can contain at most one INTO clause') } - if(f) f.forEach(info => info.table && tableList.add(`select::${info.db}::${info.table}`)); + if(f) f.forEach(info => info.table && tableList.add(`select::${[info.db, info.schema].filter(Boolean).join('.') || null}::${info.table}`)); return { with: cte, type: 'select', @@ -2560,7 +2560,6 @@ table_name } / dt:ident __ DOT __ STAR { // => IGNORE - tableList.add(`select::${dt}::(.*)`); return { db: dt, table: '*', @@ -2777,10 +2776,11 @@ update_stmt */ const dbObj = {} if (t) t.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { db, as, schema, table, join } = tableInfo const action = join ? 'select' : 'update' - if (db) dbObj[table] = db - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [db, schema].filter(Boolean).join('.') || null + if (db) dbObj[table] = fullName + if (table) tableList.add(`${action}::${fullName}::${table}`) }); if(l) { l.forEach(col => { @@ -2824,15 +2824,17 @@ delete_stmt => AstStatement */ if(f) f.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { db, as, schema, table, join } = tableInfo const action = join ? 'select' : 'delete' - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [db, schema].filter(Boolean).join('.') || null + if (table) tableList.add(`${action}::${fullName}::${table}`) if (!join) columnList.add(`delete::${table}::(.*)`); }); if (t === null && f.length === 1) { const tableInfo = f[0] t = [{ db: tableInfo.db, + schema: tableInfo.schema, table: tableInfo.table, as: tableInfo.as, addition: true, @@ -2959,7 +2961,7 @@ replace_insert_stmt => AstStatement */ if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) t.as = null } if (c) { @@ -2998,7 +3000,7 @@ insert_no_columns_stmt r:returning_stmt? { // => AstStatement if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) columnList.add(`insert::${t.table}::(.*)`); t.as = null } diff --git a/pegjs/transactsql.pegjs b/pegjs/transactsql.pegjs index 5b38c108..8cdcb32d 100644 --- a/pegjs/transactsql.pegjs +++ b/pegjs/transactsql.pegjs @@ -409,7 +409,7 @@ create_table_stmt ir: (KW_IGNORE / KW_REPLACE)? __ as: KW_AS? __ qe: union_stmt? { - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.server, tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -433,7 +433,7 @@ create_table_stmt ife:if_not_exists_stmt? __ t:table_ref_list __ lt:create_like_table { - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.server, tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -718,7 +718,7 @@ drop_stmt r:KW_TABLE __ ife: if_exists? __ t:table_ref_list { - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.server, tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -782,7 +782,7 @@ truncate_stmt = a:KW_TRUNCATE __ kw:KW_TABLE? __ t:table_ref_list { - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.server, tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -828,7 +828,7 @@ alter_view_stmt w:(KW_WITH __ view_attribute_list)? __ KW_AS __ s:select_stmt_nake __ e:view_with? { - if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${table.db}::${table.table}`)); + if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${[table.server, table.db, table.schema].filter(Boolean).join('.') || null}::${table.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -849,7 +849,7 @@ alter_table_stmt KW_TABLE __ t:table_ref_list __ e:alter_action_list { - if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${table.db}::${table.table}`)); + if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${[table.server, table.db, table.schema].filter(Boolean).join('.') || null}::${table.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1238,7 +1238,7 @@ rename_stmt = KW_RENAME __ KW_TABLE __ t:table_to_list { - t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${dt.db}::${dt.table}`))) + t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${[dt.server, dt.db, dt.schema].filter(Boolean).join('.') || null}::${dt.table}`))) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1355,7 +1355,7 @@ lock_type lock_table = t:table_base __ lt:lock_type { - tableList.add(`lock::${t.db}::${t.table}`) + tableList.add(`lock::${[t.server, t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) return { table: t, lock_type: lt @@ -1436,7 +1436,7 @@ select_stmt_nake o:order_by_clause? __ l:limit_clause? __ fx:for_xml? { - if(f) f.forEach(info => info.table && tableList.add(`select::${info.db}::${info.table}`)); + if(f) f.forEach(info => info.table && tableList.add(`select::${[info.server, info.db, info.schema].filter(Boolean).join('.') || null}::${info.table}`)); return { with: cte, type: 'select', @@ -1974,10 +1974,11 @@ update_stmt w:where_clause? { const dbObj = {} if (t) t.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { server, db, schema, as, table, join } = tableInfo const action = join ? 'select' : 'update' - if (db) dbObj[table] = db - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [server, db, schema].filter(Boolean).join('.') || null + if (db) dbObj[table] = fullName + if (table) tableList.add(`${action}::${fullName}::${table}`) }); if(l) { l.forEach(col => { @@ -2007,15 +2008,17 @@ delete_stmt f:from_clause __ w:where_clause? { if(f) f.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { server, db, schema, as, table, join } = tableInfo const action = join ? 'select' : 'delete' - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [server, db, schema].filter(Boolean).join('.') || null + if (table) tableList.add(`${action}::${fullName}::${table}`) if (!join) columnList.add(`delete::${table}::(.*)`); }); if (t === null && f.length === 1) { const tableInfo = f[0] t = [{ db: tableInfo.db, + schema: tableInfo.schema, table: tableInfo.table, as: tableInfo.as, addition: true @@ -2068,7 +2071,7 @@ replace_insert_stmt p:insert_partition? __ LPAREN __ c:column_list __ RPAREN __ v:insert_value_clause { if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.server, t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) t.as = null } if (c) { @@ -2103,7 +2106,7 @@ insert_no_columns_stmt p:insert_partition? __ v:insert_value_clause { if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.server, t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) columnList.add(`insert::${t.table}::(.*)`); t.as = null } @@ -2421,7 +2424,7 @@ column_ref obj.db = db[0] obj.schema = schema[0] } - const fullTableName = [obj.db, obj.schema, obj.table].filter(Boolean).join('.') || 'null' + const fullTableName = [obj.db, obj.schema, obj.table].filter(Boolean).join('.') || null || 'null' columnList.add(`select::${fullTableName}::${col}`); return { type: 'column_ref', diff --git a/pegjs/trino.pegjs b/pegjs/trino.pegjs index cfd83c5a..9a5681c3 100644 --- a/pegjs/trino.pegjs +++ b/pegjs/trino.pegjs @@ -556,7 +556,7 @@ create_table_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -588,7 +588,7 @@ create_table_stmt } => AstStatement; */ - if(t) t.forEach(tt => tableList.add(`create::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`create::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1043,7 +1043,7 @@ drop_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1095,7 +1095,7 @@ truncate_stmt } => AstStatement */ - if(t) t.forEach(tt => tableList.add(`${a}::${tt.db}::${tt.table}`)); + if(t) t.forEach(tt => tableList.add(`${a}::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1279,7 +1279,7 @@ alter_table_stmt } => AstStatement */ - if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${table.db}::${table.table}`)); + if (t && t.length > 0) t.forEach(table => tableList.add(`alter::${[table.db, table.schema].filter(Boolean).join('.') || null}::${table.table}`)); return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1877,7 +1877,7 @@ rename_stmt } => AstStatement */ - t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${dt.db}::${dt.table}`))) + t.forEach(tg => tg.forEach(dt => dt.table && tableList.add(`rename::${[dt.db, dt.schema].filter(Boolean).join('.') || null}::${dt.table}`))) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -1932,7 +1932,7 @@ lock_stmt => AstStatement */ - if (t) t.forEach(tt => tableList.add(`lock::${tt.db}::${tt.table}`)) + if (t) t.forEach(tt => tableList.add(`lock::${[tt.db, tt.schema].filter(Boolean).join('.') || null}::${tt.table}`)) return { tableList: Array.from(tableList), columnList: columnListTableAlias(columnList), @@ -2113,7 +2113,7 @@ select_stmt_nake_base if ((ci && fi) || (ci && li) || (fi && li) || (ci && fi && li)) { throw new Error('A given SQL statement can contain at most one INTO clause') } - if(f) f.forEach(info => info.table && tableList.add(`select::${info.db}::${info.table}`)); + if(f) f.forEach(info => info.table && tableList.add(`select::${[info.db, info.schema].filter(Boolean).join('.') || null}::${info.table}`)); return { type: 'select', options: opts, @@ -2521,7 +2521,6 @@ table_name } / dt:ident __ DOT __ STAR { // => IGNORE - tableList.add(`select::${dt}::(.*)`); return { db: dt, table: '*', @@ -2734,10 +2733,11 @@ update_stmt */ const dbObj = {} if (t) t.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { db, as, schema, table, join } = tableInfo const action = join ? 'select' : 'update' - if (db) dbObj[table] = db - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [db, schema].filter(Boolean).join('.') || null + if (db) dbObj[table] = fullName + if (table) tableList.add(`${action}::${fullName}::${table}`) }); if(l) { l.forEach(col => { @@ -2781,15 +2781,17 @@ delete_stmt => AstStatement */ if(f) f.forEach(tableInfo => { - const { db, as, table, join } = tableInfo + const { db, schema, as, table, join } = tableInfo const action = join ? 'select' : 'delete' - if (table) tableList.add(`${action}::${db}::${table}`) + const fullName = [db, schema].filter(Boolean).join('.') || null + if (table) tableList.add(`${action}::${fullName}::${table}`) if (!join) columnList.add(`delete::${table}::(.*)`); }); if (t === null && f.length === 1) { const tableInfo = f[0] t = [{ db: tableInfo.db, + schema: tableInfo.schema, table: tableInfo.table, as: tableInfo.as, addition: true, @@ -2916,7 +2918,7 @@ replace_insert_stmt => AstStatement */ if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) t.as = null } if (c) { @@ -2955,7 +2957,7 @@ insert_no_columns_stmt r:returning_stmt? { // => AstStatement if (t) { - tableList.add(`insert::${t.db}::${t.table}`) + tableList.add(`insert::${[t.db, t.schema].filter(Boolean).join('.') || null}::${t.table}`) columnList.add(`insert::${t.table}::(.*)`); t.as = null } diff --git a/test/snowflake.spec.js b/test/snowflake.spec.js index fb88aab1..55d5aecc 100644 --- a/test/snowflake.spec.js +++ b/test/snowflake.spec.js @@ -455,4 +455,25 @@ describe('snowflake', () => { expect(getParsedSql(sql[0], opt)).to.equal(sql[1]) }) }) + + describe('white list check db.schema::table', () => { + it('should check pass db.schema.table', () => { + let sql = 'SELECT * from foo.bar.baz' + let tableList = parser.tableList(sql, opt) + expect(tableList).to.be.eql([ + 'select::foo.bar::baz' + ]) + expect(parser.whiteListCheck(sql, ['select::foo.bar::baz'], opt)).to.be.undefined + sql = 'SELECT * from foo.baz' + tableList = parser.tableList(sql, opt) + expect(tableList).to.be.eql([ + 'select::foo::baz' + ]) + expect(parser.whiteListCheck(sql, ['select::foo::baz'], opt)).to.be.undefined + }) + it('should throw error when db.schema.table not match', () => { + const sql = 'SELECT * from foo.bar.baz' + expect(() => parser.whiteListCheck(sql, ['select::foo:baz'], opt)).to.throw("authority = 'select::foo.bar::baz' is required in table whiteList to execute SQL = 'SELECT * from foo.bar.baz'") + }) + }) })