Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

L029: Optionally check quoted identifiers in addition to naked identifiers #1775

Merged
merged 11 commits into from
Oct 31, 2021
Merged
1 change: 1 addition & 0 deletions src/sqlfluff/core/default_config.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ force_enable = False

[sqlfluff:rules:L029] # Keyword identifiers
unquoted_identifiers_policy = aliases
quoted_identifiers_policy = none

[sqlfluff:rules:L030] # Function names
capitalisation_policy = consistent
Expand Down
4 changes: 4 additions & 0 deletions src/sqlfluff/core/rules/config_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
"validation": ["all", "aliases", "column_aliases"],
"definition": "Types of unquoted identifiers to flag violations for",
},
"quoted_identifiers_policy": {
"validation": ["all", "aliases", "column_aliases", "none"],
"definition": "Types of quoted identifiers to flag violations for",
},
"capitalisation_policy": {
"validation": ["consistent", "upper", "lower", "capitalise"],
"definition": "The capitalisation policy to enforce",
Expand Down
8 changes: 5 additions & 3 deletions src/sqlfluff/rules/L014.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
from sqlfluff.rules.L010 import Rule_L010


def unquoted_ids_policy_applicable(
def identifiers_policy_applicable(
policy: str, parent_stack: Tuple[BaseSegment, ...]
) -> bool:
"""Does `unquoted_identifiers_policy` apply to this segment?"""
"""Does `(un)quoted_identifiers_policy` apply to this segment?"""
jpers36 marked this conversation as resolved.
Show resolved Hide resolved
if policy == "all":
return True
if policy == "none":
return False
is_alias = parent_stack and parent_stack[-1].is_type(
"alias_expression", "column_definition", "with_compound_statement"
)
Expand Down Expand Up @@ -70,7 +72,7 @@ class Rule_L014(Rule_L010):
_description_elem = "Unquoted identifiers"

def _eval(self, context: RuleContext) -> LintResult:
if unquoted_ids_policy_applicable(
if identifiers_policy_applicable(
self.unquoted_identifiers_policy, context.parent_stack # type: ignore
):
return super()._eval(context=context)
Expand Down
31 changes: 23 additions & 8 deletions src/sqlfluff/rules/L029.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from sqlfluff.core.rules.base import BaseRule, LintResult, RuleContext
from sqlfluff.core.rules.doc_decorators import document_configuration
from sqlfluff.rules.L014 import unquoted_ids_policy_applicable
from sqlfluff.rules.L014 import identifiers_policy_applicable


@document_configuration
Expand All @@ -30,18 +30,33 @@ class Rule_L029(BaseRule):

"""

config_keywords = ["unquoted_identifiers_policy"]
config_keywords = ["unquoted_identifiers_policy", "quoted_identifiers_policy"]

def _eval(self, context: RuleContext) -> Optional[LintResult]:
"""Keywords should not be used as identifiers."""
if (
context.segment.name == "naked_identifier"
and unquoted_ids_policy_applicable(
self.unquoted_identifiers_policy, context.parent_stack # type: ignore
(
context.segment.name == "naked_identifier"
and identifiers_policy_applicable(
self.unquoted_identifiers_policy, context.parent_stack # type: ignore
)
and (
context.segment.raw.upper()
in context.dialect.sets("unreserved_keywords")
)
)
and (
context.segment.raw.upper()
in context.dialect.sets("unreserved_keywords")
) or (
(
context.segment.name == "quoted_identifier"
and identifiers_policy_applicable(
self.quoted_identifiers_policy, context.parent_stack # type: ignore
)
and (
context.segment.raw.upper()[1:-1]
in context.dialect.sets("unreserved_keywords")
or context.segment.raw.upper()[1:-1]
in context.dialect.sets("reserved_keywords")
)
)
):
return LintResult(anchor=context.segment)
Expand Down
95 changes: 87 additions & 8 deletions test/fixtures/rules/std_rule_cases/L029.yml
Original file line number Diff line number Diff line change
@@ -1,38 +1,117 @@
rule: L029

test_pass_valid_identifiers_1:
test_pass_valid_identifier:
pass_str: CREATE TABLE artist(artist_name TEXT)

test_fail_keyword_as_identifier_1:
test_fail_keyword_as_identifier_column:
fail_str: CREATE TABLE artist(create TEXT)

test_fail_keyword_as_identifier_2:
test_fail_keyword_as_identifier_column_alias:
fail_str: SELECT 1 as parameter

test_fail_keyword_as_identifier_3:
test_fail_keyword_as_identifier_table_alias:
fail_str: SELECT x FROM tbl AS parameter

test_pass_valid_identifiers_2:
test_pass_valid_identifier_not_alias:
# should pass on default config as not alias
pass_str: SELECT parameter

test_fail_keyword_as_identifier_4:
test_fail_keyword_as_identifier_not_alias_all:
fail_str: SELECT parameter
configs:
rules:
L029:
unquoted_identifiers_policy: all

test_pass_valid_identifiers_3:
test_pass_valid_identifier_table_alias_column_alias_config:
pass_str: SELECT x FROM tbl AS parameter
configs:
rules:
L029:
unquoted_identifiers_policy: column_aliases

test_fail_keyword_as_identifier_5:
test_fail_keyword_as_identifier_column_alias_config:
fail_str: SELECT x AS date FROM tbl AS parameter
configs:
rules:
L029:
unquoted_identifiers_policy: column_aliases

test_pass_valid_quoted_identifier:
pass_str: CREATE TABLE [artist]([artist_name] TEXT)
configs:
rules:
L029:
quoted_identifiers_policy: aliases
core:
dialect: tsql
tunetheweb marked this conversation as resolved.
Show resolved Hide resolved

test_fail_keyword_as_quoted_identifier_column:
fail_str: CREATE TABLE "artist"("create" TEXT)
configs:
rules:
L029:
quoted_identifiers_policy: aliases

test_pass_keyword_as_quoted_identifier_column_none_policy:
pass_str: CREATE TABLE "artist"("create" TEXT)
configs:
rules:
L029:
quoted_identifiers_policy: none

test_fail_keyword_as_quoted_identifier_column_alias:
fail_str: SELECT 1 as [parameter]
configs:
rules:
L029:
quoted_identifiers_policy: aliases
core:
dialect: tsql

test_fail_keyword_as_quoted_identifier_table_alias:
fail_str: SELECT [x] FROM [tbl] AS [parameter]
configs:
rules:
L029:
quoted_identifiers_policy: aliases
core:
dialect: tsql

test_pass_valid_quoted_identifier_not_alias:
# should pass on default config as not alias
pass_str: SELECT [parameter]
configs:
rules:
L029:
quoted_identifiers_policy: aliases
core:
dialect: tsql

test_fail_keyword_as_quoted_identifier_not_alias_all:
fail_str: SELECT [parameter]
configs:
rules:
L029:
quoted_identifiers_policy: all
core:
dialect: tsql

test_pass_valid_quoted_identifier_table_alias_column_alias_config:
pass_str: SELECT [x] FROM [tbl] AS [parameter]
configs:
rules:
L029:
quoted_identifiers_policy: column_aliases
core:
dialect: tsql

test_fail_keyword_as_quoted_identifier_column_alias_config:
fail_str: SELECT [x] AS [date] FROM [tbl] AS [parameter]
configs:
rules:
L029:
quoted_identifiers_policy: column_aliases
core:
dialect: tsql