Skip to content

Commit da144a4

Browse files
T-SantosSantos, Tyler (Boston)
andauthored
MSSQL Unqualified Schema Table Parsing (#530)
Co-authored-by: Santos, Tyler (Boston) <tyler.santos@man.com>
1 parent 8bdc496 commit da144a4

2 files changed

Lines changed: 42 additions & 8 deletions

File tree

sql_metadata/parser.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ def columns(self) -> List[str]:
219219
self._handle_column_save(token=token, columns=columns)
220220

221221
elif token.is_column_name_inside_insert_clause:
222-
column = str(token.value).strip("`")
222+
column = str(token.value)
223223
self._add_to_columns_subsection(
224224
keyword=token.last_keyword_normalized, column=column
225225
)
@@ -369,10 +369,8 @@ def tables(self) -> List[str]:
369369
and self.query_type == "INSERT"
370370
):
371371
continue
372-
373-
table_name = str(token.value.strip("`"))
374372
token.token_type = TokenType.TABLE
375-
tables.append(table_name)
373+
tables.append(str(token.value))
376374

377375
self._tables = tables - with_names
378376
return self._tables
@@ -1013,6 +1011,8 @@ def _is_token_part_of_complex_identifier(
10131011
Checks if token is a part of complex identifier like
10141012
<schema>.<table>.<column> or <table/sub_query>.<column>
10151013
"""
1014+
if token.is_keyword:
1015+
return False
10161016
return str(token) == "." or (
10171017
index + 1 < self.tokens_length
10181018
and str(self.non_empty_tokens[index + 1]) == "."
@@ -1026,16 +1026,19 @@ def _combine_qualified_names(self, index: int, token: SQLToken) -> None:
10261026
is_complex = True
10271027
while is_complex:
10281028
value, is_complex = self._combine_tokens(index=index, value=value)
1029-
index = index - 2
1029+
index = index - 1
10301030
token.value = value
10311031

10321032
def _combine_tokens(self, index: int, value: str) -> Tuple[str, bool]:
10331033
"""
10341034
Checks if complex identifier is longer and follows back until it's finished
10351035
"""
1036-
if index > 1 and str(self.non_empty_tokens[index - 1]) == ".":
1037-
prev_value = self.non_empty_tokens[index - 2].value.strip("`").strip('"')
1038-
value = f"{prev_value}.{value}"
1036+
if index > 1:
1037+
prev_value = self.non_empty_tokens[index - 1]
1038+
if not self._is_token_part_of_complex_identifier(prev_value, index - 1):
1039+
return value, False
1040+
prev_value = str(prev_value).strip("`")
1041+
value = f"{prev_value}{value}"
10391042
return value, True
10401043
return value, False
10411044

test/test_mssql_server.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,37 @@
1+
import pytest
2+
13
from sql_metadata.parser import Parser
24

35

6+
@pytest.mark.parametrize(
7+
"query, expected",
8+
[
9+
pytest.param(
10+
"SELECT * FROM mydb..test_table",
11+
["mydb..test_table"],
12+
id="Default schema, db qualified",
13+
),
14+
pytest.param(
15+
"SELECT * FROM ..test_table",
16+
["..test_table"],
17+
id="Default schema, db unqualified",
18+
),
19+
pytest.param(
20+
"SELECT * FROM [mydb].[dbo].[test_table]",
21+
["[mydb].[dbo].[test_table]"],
22+
id="With object identifier delimiters",
23+
),
24+
pytest.param(
25+
"SELECT * FROM [my_server].[mydb].[dbo].[test_table]",
26+
["[my_server].[mydb].[dbo].[test_table]"],
27+
id="With linked-server and object identifier delimiters",
28+
),
29+
],
30+
)
31+
def test_simple_queries_tables(query, expected):
32+
assert Parser(query).tables == expected
33+
34+
435
def test_sql_server_cte():
536
"""
637
Tests support for SQL Server's common table expression (CTE).

0 commit comments

Comments
 (0)