sql-error-categorizer 0.1.4__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/PKG-INFO +1 -1
  2. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/pyproject.toml +1 -1
  3. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/__init__.py +1 -1
  4. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/catalog/builder/__init__.py +12 -6
  5. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/detectors/logical.py +11 -4
  6. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/test_detector.py +2 -2
  7. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/3_log/test_058_join_on_incorrect_table.py +6 -0
  8. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/3_log/test_059_join_when_join_needs_to_be_omitted.py +6 -1
  9. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/3_log/test_062_missing_join.py +6 -0
  10. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/3_log/test_070_extraneous_column_in_select.py +6 -0
  11. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/3_log/test_071_missing_column_from_select.py +6 -0
  12. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/3_log/test_072_missing_distinct_from_select.py +6 -0
  13. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/3_log/test_073_missing_as_from_select.py +7 -1
  14. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/.gitignore +0 -0
  15. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/.readthedocs.yaml +0 -0
  16. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/LICENSE +0 -0
  17. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/Makefile +0 -0
  18. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/README.md +0 -0
  19. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/datasets/catalogs/constraints.json +0 -0
  20. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/datasets/catalogs/miedema.json +0 -0
  21. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/datasets/sql/constraints.sql +0 -0
  22. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/datasets/sql/miedema.sql +0 -0
  23. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/docs/Makefile +0 -0
  24. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/docs/conf.py +0 -0
  25. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/docs/index.rst +0 -0
  26. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/docs/make.bat +0 -0
  27. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/docs/requirements.txt +0 -0
  28. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/requirements.txt +0 -0
  29. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/catalog/__init__.py +0 -0
  30. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/catalog/builder/queries.py +0 -0
  31. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/catalog/catalog.py +0 -0
  32. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/catalog/column.py +0 -0
  33. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/catalog/constraint.py +0 -0
  34. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/catalog/schema.py +0 -0
  35. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/catalog/table.py +0 -0
  36. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/detectors/__init__.py +0 -0
  37. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/detectors/base.py +0 -0
  38. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/detectors/complications.py +0 -0
  39. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/detectors/semantic.py +0 -0
  40. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/detectors/syntax.py +0 -0
  41. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/__init__.py +0 -0
  42. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/extractors.py +0 -0
  43. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/query.py +0 -0
  44. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/set_operations/__init__.py +0 -0
  45. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/set_operations/binary_set_operation.py +0 -0
  46. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/set_operations/select.py +0 -0
  47. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/set_operations/set_operation.py +0 -0
  48. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/smt.py +0 -0
  49. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/tokenized_sql.py +0 -0
  50. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/typechecking/__init__.py +0 -0
  51. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/typechecking/base.py +0 -0
  52. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/typechecking/binary_ops.py +0 -0
  53. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/typechecking/functions.py +0 -0
  54. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/typechecking/predicates.py +0 -0
  55. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/typechecking/primitives.py +0 -0
  56. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/typechecking/queries.py +0 -0
  57. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/typechecking/types.py +0 -0
  58. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/typechecking/unary_ops.py +0 -0
  59. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/query/typechecking/util.py +0 -0
  60. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/sql_errors.py +0 -0
  61. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/util/__init__.py +0 -0
  62. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/util/ast/__init__.py +0 -0
  63. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/util/ast/column.py +0 -0
  64. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/util/ast/function.py +0 -0
  65. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/util/ast/subquery.py +0 -0
  66. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/util/ast/table.py +0 -0
  67. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/util/sql.py +0 -0
  68. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/src/sql_error_categorizer/util/tokens.py +0 -0
  69. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/__init__.py +0 -0
  70. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_002_ambiguous_column.py +0 -0
  71. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_004_undefined_column.py +0 -0
  72. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_005_undefined_function.py +0 -0
  73. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_006_undefined_parameter.py +0 -0
  74. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_007_undefined_tables.py +0 -0
  75. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_008_invalid_schema_names.py +0 -0
  76. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_009_misspellings.py +0 -0
  77. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_014_aggregate_function_outside_select_or_having.py +0 -0
  78. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_015_nested_aggregate_functions.py +0 -0
  79. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_016_extraneous_omitted_grouping_column.py +0 -0
  80. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_017_having_without_group_by.py +0 -0
  81. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_019_using_where_twice.py +0 -0
  82. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_020_missing_from.py +0 -0
  83. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_021_comparison_with_null.py +0 -0
  84. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_022_038_additional_omitted_semicolons.py +0 -0
  85. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_024_duplicate_clause.py +0 -0
  86. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_026_too_many_columns_in_subquery.py +0 -0
  87. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_030_keywords_order.py +0 -0
  88. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_034_curly_square_or_unmatched_brackets.py +0 -0
  89. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/1_syn/test_037_nonstandard_operators.py +0 -0
  90. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/2_sem/test_040_tautological_inconsistent_expressions.py +0 -0
  91. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/2_sem/test_041_distinct_sum_avg.py +0 -0
  92. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/2_sem/test_043_wildcards_without_like.py +0 -0
  93. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/2_sem/test_044_incorrect_wildcards.py +0 -0
  94. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/4_com/test_083_unnecessary_distinct_in_select.py +0 -0
  95. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/4_com/test_088_like_no_wildcards.py +0 -0
  96. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/4_com/test_092_unnecessary_distinct_in_aggregate_function.py +0 -0
  97. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/4_com/test_095_group_by_with_singleton_groups.py +0 -0
  98. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/4_com/test_097_group_by_can_be_replaced_by_distinct.py +0 -0
  99. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/detectors/4_com/test_100_order_by_in_subquery.py +0 -0
  100. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/query/test_extractors.py +0 -0
  101. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/query/test_query.py +0 -0
  102. {sql_error_categorizer-0.1.4 → sql_error_categorizer-0.1.6}/tests/query/test_typechecking.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sql_error_categorizer
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: This project analyses SQL statements and labels possible errors or complications.
5
5
  Project-URL: Repository, https://github.com/DavidePonzini/sql_error_categorizer
6
6
  Project-URL: Documentation, https://sql-error-categorizer.readthedocs.io/en/latest/index.html
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sql_error_categorizer"
7
- version = "0.1.4"
7
+ version = "0.1.6"
8
8
  authors = [
9
9
  { name="Davide Ponzini", email="davide.ponzini95@gmail.com" },
10
10
  ]
@@ -5,7 +5,7 @@ from .detectors import BaseDetector as _BaseDetector, Detector as _Detector
5
5
 
6
6
  # Public API
7
7
  from .sql_errors import SqlErrors
8
- from .catalog import Catalog, build_catalog, load_catalog
8
+ from .catalog import Catalog, build_catalog, load_catalog, build_catalog_from_postgres
9
9
  from .detectors import SyntaxErrorDetector, SemanticErrorDetector, LogicalErrorDetector, ComplicationDetector, DetectedError
10
10
 
11
11
  def get_errors(query_str: str,
@@ -54,12 +54,18 @@ def build_catalog(columns_info: list[CatalogColumnInfo], unique_constraints_info
54
54
  result = Catalog()
55
55
 
56
56
  for column in columns_info:
57
- schema_name, table_name, column_name, column_type, numeric_precision, numeric_scale, is_nullable, fk_schema, fk_table, fk_column = column
58
-
59
- result.add_column(schema_name, table_name, column_name,
60
- column_type, numeric_precision, numeric_scale,
61
- is_nullable,
62
- fk_schema, fk_table, fk_column)
57
+ result.add_column(
58
+ schema_name=column.schema_name,
59
+ table_name=column.table_name,
60
+ column_name=column.column_name,
61
+ column_type=column.column_type,
62
+ numeric_precision=column.numeric_precision,
63
+ numeric_scale=column.numeric_scale,
64
+ is_nullable=column.is_nullable,
65
+ fk_schema=column.foreign_key_schema,
66
+ fk_table=column.foreign_key_table,
67
+ fk_column=column.foreign_key_column,
68
+ )
63
69
 
64
70
  for constraint in unique_constraints_info:
65
71
  columns = set(constraint.columns.strip('{}').split(',')) # Postgres returns {col1,col2,...}
@@ -27,7 +27,13 @@ class LogicalErrorDetector(BaseDetector):
27
27
  update_query=update_query,
28
28
  )
29
29
 
30
- def run(self) -> list[DetectedError]:
30
+ def run(self) -> list[DetectedError]:
31
+
32
+ # All logical errors require at least one solution to compare against
33
+ # If no solutions are provided, we cannot perform logical error detection
34
+ if not self.solutions:
35
+ return []
36
+
31
37
  results: list[DetectedError] = super().run()
32
38
 
33
39
  checks = [
@@ -182,9 +188,6 @@ class LogicalErrorDetector(BaseDetector):
182
188
  3. Incorrect Join: A table is included, but it is not the correct one needed for the join.
183
189
  '''
184
190
 
185
- if not self.solutions:
186
- return []
187
-
188
191
  @dataclass(frozen=True)
189
192
  class TableCol:
190
193
  table: str
@@ -434,6 +437,10 @@ class LogicalErrorDetector(BaseDetector):
434
437
  return []
435
438
 
436
439
  def log_73_missing_as_from_select(self) -> list[DetectedError]:
440
+ '''
441
+ Flags when AS aliases are missing from required columns in the SELECT clause.
442
+ '''
443
+
437
444
  results: list[DetectedError] = []
438
445
 
439
446
  # ensure we have the correct columns in both amount and source
@@ -1,5 +1,5 @@
1
1
  from sql_error_categorizer.detectors import Detector
2
- from sql_error_categorizer import load_catalog, build_catalog, SyntaxErrorDetector, SemanticErrorDetector, LogicalErrorDetector, ComplicationDetector
2
+ from sql_error_categorizer import load_catalog, build_catalog_from_postgres, SyntaxErrorDetector, SemanticErrorDetector, LogicalErrorDetector, ComplicationDetector
3
3
 
4
4
  def make_catalog(file: str) -> None:
5
5
  '''Utility function to build a catalog from a source file'''
@@ -7,7 +7,7 @@ def make_catalog(file: str) -> None:
7
7
  with open(f'datasets/sql/{file}.sql') as f:
8
8
  content = f.read()
9
9
 
10
- cat = build_catalog(content, hostname='localhost', port=5432, user='postgres', password='password', schema=file, create_temp_schema=True)
10
+ cat = build_catalog_from_postgres(content, hostname='localhost', port=5432, user='postgres', password='password', schema=file, create_temp_schema=True)
11
11
 
12
12
  cat.save_json(f'datasets/catalogs/{file}.json')
13
13
 
@@ -107,6 +107,12 @@ def test_wrong(query: str, solutions: list[str], expected_errors: list[tuple[str
107
107
  ],
108
108
  None
109
109
  ),
110
+ (
111
+ # no solutions (return no errors)
112
+ 'SELECT a, b, c FROM table1 JOIN table2 ON table1.id = table2.id;',
113
+ [],
114
+ None,
115
+ ),
110
116
  # subqueries
111
117
  (
112
118
  # expected: table1 table2 table3 table4
@@ -107,7 +107,12 @@ def test_wrong(query: str, solutions: list[str], expected_errors: list[tuple[str
107
107
  ],
108
108
  None
109
109
  ),
110
-
110
+ (
111
+ # no solutions (return no errors)
112
+ 'SELECT a, b, c FROM table1 JOIN table2 ON table1.id = table2.id;',
113
+ [],
114
+ None,
115
+ ),
111
116
  # subqueries
112
117
  (
113
118
  # expected: table1 table2 table3 table4
@@ -106,6 +106,12 @@ def test_wrong(query: str, solutions: list[str], expected_errors: list[tuple[str
106
106
  ],
107
107
  None,
108
108
  ),
109
+ (
110
+ # no solutions (return no errors)
111
+ 'SELECT a, b, c FROM table1 JOIN table2 ON table1.id = table2.id;',
112
+ [],
113
+ None,
114
+ ),
109
115
  # subqueries
110
116
  (
111
117
  # expected: table1 table2 table3 table4
@@ -84,6 +84,12 @@ def test_wrong(query, solutions, schema, search_path, expected_len, expected_col
84
84
  ['SELECT cid, cname FROM customer;'],
85
85
  'miedema',
86
86
  ),
87
+ (
88
+ # no solutions (return no errors)
89
+ 'SELECT a, b, c FROM table1;',
90
+ [],
91
+ None,
92
+ ),
87
93
  # subqueries
88
94
  (
89
95
  'SELECT a, (SELECT b FROM table2) as sub_col FROM table1;',
@@ -84,6 +84,12 @@ def test_wrong(query, solutions, schema, search_path, expected_len, expected_col
84
84
  ['SELECT cid FROM customer;'],
85
85
  'miedema',
86
86
  ),
87
+ (
88
+ # no solutions (return no errors)
89
+ 'SELECT a, b, c FROM table1;',
90
+ [],
91
+ None,
92
+ ),
87
93
  # subqueries
88
94
  (
89
95
  'SELECT a, (SELECT b FROM table2) as sub_col FROM table1;',
@@ -59,6 +59,12 @@ def test_wrong(query, solutions, schema):
59
59
  ['SELECT DISTINCT street FROM customer;'],
60
60
  'miedema'
61
61
  ),
62
+ (
63
+ # no solutions (return no errors)
64
+ 'SELECT a, b, c FROM table1;',
65
+ [],
66
+ None,
67
+ ),
62
68
  # Subqueries
63
69
  (
64
70
  'SELECT DISTINCT a, (SELECT b FROM table2) as sub_col FROM table1;',
@@ -47,7 +47,13 @@ def test_wrong(query, solutions, schema, expected):
47
47
  'SELECT cid AS cname, cname AS cid FROM customer;',
48
48
  ['SELECT cid AS cname, cname AS cid FROM customer;'],
49
49
  'miedema',
50
- )
50
+ ),
51
+ (
52
+ # no solutions (return no errors)
53
+ 'SELECT a, b, c FROM table1;',
54
+ [],
55
+ None,
56
+ ),
51
57
  # subqueries -- Not applicable
52
58
  # CTEs -- Not applicable
53
59
  ])