sql-data-guard 0.1.3__tar.gz → 0.1.4__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 (27) hide show
  1. {sql_data_guard-0.1.3/src/sql_data_guard.egg-info → sql_data_guard-0.1.4}/PKG-INFO +1 -1
  2. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/pyproject.toml +1 -1
  3. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/src/sql_data_guard/restriction_verification.py +39 -16
  4. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/src/sql_data_guard/sql_data_guard.py +26 -13
  5. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4/src/sql_data_guard.egg-info}/PKG-INFO +1 -1
  6. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/test/test_sql_guard_curr_unit.py +113 -68
  7. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/test/test_sql_guard_updates_unit.py +9 -40
  8. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/LICENSE.md +0 -0
  9. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/README.md +0 -0
  10. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/setup.cfg +0 -0
  11. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/src/sql_data_guard/__init__.py +0 -0
  12. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/src/sql_data_guard/rest/__init__.py +0 -0
  13. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/src/sql_data_guard/rest/sql_data_guard_rest.py +0 -0
  14. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/src/sql_data_guard/restriction_validation.py +0 -0
  15. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/src/sql_data_guard/verification_context.py +0 -0
  16. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/src/sql_data_guard/verification_utils.py +0 -0
  17. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/src/sql_data_guard.egg-info/SOURCES.txt +0 -0
  18. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/src/sql_data_guard.egg-info/dependency_links.txt +0 -0
  19. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/src/sql_data_guard.egg-info/requires.txt +0 -0
  20. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/src/sql_data_guard.egg-info/top_level.txt +0 -0
  21. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/test/test_duckdb_unit.py +0 -0
  22. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/test/test_rest_api_unit.py +0 -0
  23. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/test/test_sql_guard_joins_unit.py +0 -0
  24. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/test/test_sql_guard_llm.py +0 -0
  25. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/test/test_sql_guard_unit.py +0 -0
  26. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/test/test_sql_guard_validation_unit.py +0 -0
  27. {sql_data_guard-0.1.3 → sql_data_guard-0.1.4}/test/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sql-data-guard
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: Safety Layer for LLM Database Interactions
5
5
  Author-email: Imperva - Threat Reseach Infra <ww.dis.imperva.threat-research-infra@thalesgroup.com>
6
6
  License: MIT License
@@ -9,7 +9,7 @@ package-dir = {"" = "src"}
9
9
  extra-index-url = ["https://pypi.org/simple"]
10
10
  [project]
11
11
  name = "sql-data-guard"
12
- version = "0.1.3"
12
+ version = "0.1.4"
13
13
  dependencies = [
14
14
  "sqlglot"
15
15
  ]
@@ -103,38 +103,61 @@ def _verify_restriction(
103
103
  Verifies if a given restriction is satisfied within an SQL expression.
104
104
 
105
105
  Args:
106
- restriction (dict): The restriction to verify, containing 'column' and 'value' keys.
106
+ restriction (dict): The restriction to verify, containing 'column' and 'value' or 'values'.
107
107
  from_table (Table): The table reference to check the restriction against.
108
- exp (list): The SQL expression to check against the restriction.
108
+ exp (Expression): The SQL expression to check against the restriction.
109
109
 
110
110
  Returns:
111
111
  bool: True if the restriction is satisfied, False otherwise.
112
112
  """
113
+
113
114
  if isinstance(exp, expr.Not):
114
115
  return False
116
+
115
117
  if isinstance(exp, expr.Paren):
116
118
  return _verify_restriction(restriction, from_table, exp.this)
117
- if not isinstance(exp.this, expr.Column):
118
- return False
119
- if not exp.this.name == restriction["column"]:
119
+
120
+ if not isinstance(exp.this, expr.Column) or exp.this.name != restriction["column"]:
120
121
  return False
122
+
121
123
  if exp.this.table and from_table.alias and exp.this.table != from_table.alias:
122
124
  return False
123
125
  if exp.this.table and not from_table.alias and exp.this.table != from_table.name:
124
126
  return False
127
+
128
+ values = _get_restriction_values(restriction) # Get correct restriction values
129
+
130
+ # Handle IN condition correctly
131
+ if isinstance(exp, expr.In):
132
+ expr_values = [str(val.this) for val in exp.expressions]
133
+ return any(v in values for v in expr_values)
134
+
135
+ # Handle EQ (=) condition
125
136
  if isinstance(exp, expr.EQ) and isinstance(exp.right, expr.Condition):
126
- if isinstance(exp.right, expr.Boolean):
127
- return exp.right.this == restriction["value"]
128
- else:
129
- values = _get_restriction_values(restriction)
130
- return exp.right.this in values
137
+ return str(exp.right.this) in values
138
+
131
139
  if isinstance(exp, expr.Between):
132
- sql_values = [v.this for v in exp.expressions]
133
- values = _get_restriction_values(restriction)
134
- return any(v in values for v in sql_values)
135
- if isinstance(exp, expr.In):
136
- values = [v.this for v in exp.expressions]
137
- return False
140
+ low, high = int(exp.args["low"].this), int(exp.args["high"].this)
141
+ if len(values) == 2: # Ensure we have exactly two values
142
+ restriction_low, restriction_high = map(int, values)
143
+ return restriction_low <= low and high <= restriction_high
144
+
145
+ if isinstance(exp, (expr.LT, expr.LTE, expr.GT, expr.GTE)) and isinstance(
146
+ exp.right, expr.Condition
147
+ ):
148
+ if restriction.get("operation") not in [">=", ">", "<=", "<"]:
149
+ return False
150
+ assert len(values) == 1
151
+ if isinstance(exp, expr.LT) and restriction["operation"] == "<":
152
+ return str(exp.right.this) < values[0]
153
+ elif isinstance(exp, expr.LTE) and restriction["operation"] == "<=":
154
+ return str(exp.right.this) <= values[0]
155
+ elif isinstance(exp, expr.GT) and restriction["operation"] == ">":
156
+ return str(exp.right.this) > values[0]
157
+ elif isinstance(exp, expr.GTE) and restriction["operation"] == ">=":
158
+ return str(exp.right.this) >= values[0]
159
+ else:
160
+ return False
138
161
  return False
139
162
 
140
163
 
@@ -77,6 +77,10 @@ def _verify_where_clause(
77
77
  select_statement: expr.Query,
78
78
  from_tables: List[expr.Table],
79
79
  ):
80
+ where_clause = select_statement.find(expr.Where)
81
+ if where_clause:
82
+ for sub in where_clause.find_all(expr.Subquery):
83
+ _verify_query_statement(sub.this, context)
80
84
  _verify_static_expression(select_statement, context)
81
85
  verify_restrictions(select_statement, context, from_tables)
82
86
 
@@ -124,10 +128,6 @@ def _has_static_expression(context: VerificationContext, exp: expr.Expression) -
124
128
 
125
129
 
126
130
  def _verify_query_statement(query_statement: expr.Query, context: VerificationContext):
127
- for select in query_statement.selects:
128
- for sub in select.find_all(expr.Subquery):
129
- _add_table_alias(sub, context)
130
- _verify_query_statement(sub.this, context)
131
131
  if isinstance(query_statement, expr.Union):
132
132
  _verify_query_statement(query_statement.left, context)
133
133
  _verify_query_statement(query_statement.right, context)
@@ -135,10 +135,16 @@ def _verify_query_statement(query_statement: expr.Query, context: VerificationCo
135
135
  for cte in query_statement.ctes:
136
136
  _add_table_alias(cte, context)
137
137
  _verify_query_statement(cte.this, context)
138
- where_clause = query_statement.find(expr.Where)
139
- if where_clause:
140
- for sub in where_clause.find_all(expr.Subquery):
141
- _verify_query_statement(sub.this, context)
138
+ from_tables = _verify_from_tables(context, query_statement)
139
+ if not context.can_fix:
140
+ return query_statement
141
+ _verify_select_clause(context, query_statement, from_tables)
142
+ _verify_where_clause(context, query_statement, from_tables)
143
+ _verify_order_by_clause(context, query_statement)
144
+ return query_statement
145
+
146
+
147
+ def _verify_from_tables(context, query_statement):
142
148
  from_tables = _get_from_clause_tables(query_statement, context)
143
149
  for t in from_tables:
144
150
  found = False
@@ -147,11 +153,14 @@ def _verify_query_statement(query_statement: expr.Query, context: VerificationCo
147
153
  found = True
148
154
  if not found:
149
155
  context.add_error(f"Table {t.name} is not allowed", False, 1)
150
- if not context.can_fix:
151
- return query_statement
152
- _verify_select_clause(context, query_statement, from_tables)
153
- _verify_where_clause(context, query_statement, from_tables)
154
- return query_statement
156
+ return from_tables
157
+
158
+
159
+ def _verify_order_by_clause(context, query_statement):
160
+ for exp_type in [expr.Order, expr.Offset]:
161
+ for exp in find_direct(query_statement, exp_type):
162
+ for sub in exp.find_all(expr.Subquery):
163
+ _verify_query_statement(sub.this, context)
155
164
 
156
165
 
157
166
  def _verify_select_clause(
@@ -159,6 +168,10 @@ def _verify_select_clause(
159
168
  select_clause: expr.Query,
160
169
  from_tables: List[expr.Table],
161
170
  ):
171
+ for select in select_clause.selects:
172
+ for sub in select.find_all(expr.Subquery):
173
+ _add_table_alias(sub, context)
174
+ _verify_query_statement(sub.this, context)
162
175
  to_remove = []
163
176
  for e in select_clause.expressions:
164
177
  if not _verify_select_clause_element(from_tables, context, e):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sql-data-guard
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: Safety Layer for LLM Database Interactions
5
5
  Author-email: Imperva - Threat Reseach Infra <ww.dis.imperva.threat-research-infra@thalesgroup.com>
6
6
  License: MIT License
@@ -3,7 +3,6 @@ import os
3
3
  import sqlite3
4
4
  from sqlite3 import Connection
5
5
  from typing import Set, Generator
6
-
7
6
  import pytest
8
7
  from sql_data_guard import verify_sql
9
8
  from conftest import verify_sql_test
@@ -25,7 +24,7 @@ class TestSQLJoins:
25
24
  "column": "price",
26
25
  "value": 100,
27
26
  "operation": ">=",
28
- } # Restriction on price column
27
+ }
29
28
  ],
30
29
  },
31
30
  {
@@ -176,7 +175,7 @@ class TestSQLJoins:
176
175
  cnn=cnn,
177
176
  data=[
178
177
  {
179
- "Product2", # Product2 has price = 100
178
+ "Product2",
180
179
  },
181
180
  {
182
181
  "Product4", # Product4 has price = 100
@@ -537,45 +536,19 @@ class TestSQLOrderDateBetweenRestrictions:
537
536
  "SELECT prod_id, prod_name, price FROM products WHERE price BETWEEN 80 AND 150",
538
537
  config,
539
538
  cnn=cnn,
540
- errors={
541
- "Missing restriction for table: products column: price value: [80, 150]"
542
- },
543
- fix="SELECT prod_id, prod_name, price FROM products WHERE (price BETWEEN 80 AND "
544
- "150) AND price BETWEEN 80 AND 150",
545
539
  data=[
546
- (1, "Product A", 120.0),
547
- (2, "Product B", 80.0),
548
- (3, "Product C", 150.0),
540
+ (1, "Product A", 120),
541
+ (2, "Product B", 80),
542
+ (3, "Product C", 150),
549
543
  ],
550
544
  )
551
545
 
552
- def test_price_not_between_restriction(self, cnn, config):
553
- sql_query = """
554
- SELECT prod_id, prod_name, price
555
- FROM products
556
- WHERE price NOT BETWEEN 80 AND 150
557
- """
558
- verify_sql_test(
559
- sql_query,
560
- config,
561
- errors={
562
- "Missing restriction for table: products column: price value: [80, 150]"
563
- },
564
- fix="SELECT prod_id, prod_name, price FROM products WHERE (NOT price BETWEEN 80 AND 150) AND price BETWEEN 80 AND 150",
565
- cnn=cnn,
566
- data=[],
567
- )
568
-
569
546
  def test_count_products_within_price_range(self, cnn, config):
570
547
  verify_sql_test(
571
548
  "SELECT COUNT(*) FROM products WHERE price BETWEEN 80 AND 150",
572
549
  config,
573
- errors={
574
- "Missing restriction for table: products column: price value: [80, 150]"
575
- },
576
- fix="SELECT COUNT(*) FROM products WHERE (price BETWEEN 80 AND 150) AND price BETWEEN 80 AND 150",
577
550
  cnn=cnn,
578
- data=[(3,)], # Expecting 3 products in this range
551
+ data=[(3,)], # Expecting 3 products
579
552
  )
580
553
 
581
554
  def test_left_join_products_with_orders(self, cnn, config):
@@ -585,12 +558,6 @@ class TestSQLOrderDateBetweenRestrictions:
585
558
  LEFT JOIN orders o ON p.prod_id = o.prod_id
586
559
  WHERE p.price BETWEEN 80 AND 150""",
587
560
  config,
588
- errors={
589
- "Missing restriction for table: products column: p.price value: [80, 150]"
590
- },
591
- fix="SELECT p.prod_name, o.order_id, COALESCE(o.quantity, 0) AS quantity FROM "
592
- "products AS p LEFT JOIN orders AS o ON p.prod_id = o.prod_id WHERE (p.price "
593
- "BETWEEN 80 AND 150) AND p.price BETWEEN 80 AND 150",
594
561
  cnn=cnn,
595
562
  data=[("Product A", 1, 10), ("Product B", 2, 5), ("Product C", 3, 7)],
596
563
  )
@@ -599,11 +566,11 @@ class TestSQLOrderDateBetweenRestrictions:
599
566
  verify_sql_test(
600
567
  "SELECT prod_name, price FROM products WHERE price < 90",
601
568
  config,
569
+ cnn=cnn,
602
570
  errors={
603
571
  "Missing restriction for table: products column: price value: [80, 150]"
604
572
  },
605
573
  fix="SELECT prod_name, price FROM products WHERE (price < 90) AND price BETWEEN 80 AND 150",
606
- cnn=cnn,
607
574
  data=[("Product B", 80)],
608
575
  )
609
576
 
@@ -613,10 +580,6 @@ class TestSQLOrderDateBetweenRestrictions:
613
580
  "FROM products "
614
581
  "WHERE price BETWEEN 80 AND 150 AND prod_category = 'CategoryA'",
615
582
  config,
616
- errors={
617
- "Missing restriction for table: products column: price value: [80, 150]"
618
- },
619
- fix="SELECT prod_id, prod_name, price, prod_category FROM products WHERE (price BETWEEN 80 AND 150 AND prod_category = 'CategoryA') AND price BETWEEN 80 AND 150",
620
583
  cnn=cnn,
621
584
  data=[
622
585
  (1, "Product A", 120, "CategoryA"),
@@ -631,10 +594,6 @@ class TestSQLOrderDateBetweenRestrictions:
631
594
  "WHERE price BETWEEN 90 AND 125 "
632
595
  "GROUP BY prod_category",
633
596
  config,
634
- errors={
635
- "Missing restriction for table: products column: price value: [80, 150]"
636
- },
637
- fix="SELECT COUNT(prod_id) AS product_count, prod_category FROM products WHERE (price BETWEEN 90 AND 125) AND price BETWEEN 80 AND 150 GROUP BY prod_category",
638
597
  cnn=cnn,
639
598
  data=[(1, "CategoryA")], # Only Product A fits in this range
640
599
  )
@@ -646,11 +605,6 @@ class TestSQLOrderDateBetweenRestrictions:
646
605
  "INNER JOIN products p ON o.prod_id = p.prod_id "
647
606
  "WHERE p.price BETWEEN 90 AND 150",
648
607
  config,
649
- errors={
650
- "Missing restriction for table: products column: p.price value: [80, 150]"
651
- },
652
- fix="SELECT o.order_id, p.prod_name, p.price FROM orders AS o INNER JOIN products AS p "
653
- "ON o.prod_id = p.prod_id WHERE (p.price BETWEEN 90 AND 150) AND p.price BETWEEN 80 AND 150",
654
608
  cnn=cnn,
655
609
  data=[
656
610
  (1, "Product A", 120),
@@ -658,31 +612,122 @@ class TestSQLOrderDateBetweenRestrictions:
658
612
  ],
659
613
  )
660
614
 
661
- def test_non_existent_product_between(self, cnn, config):
615
+ def test_existent_product_between(self, cnn, config):
662
616
  verify_sql_test(
663
617
  "SELECT prod_id, prod_name, price "
664
618
  "FROM products "
665
- "WHERE price BETWEEN 200 AND 300",
619
+ "WHERE price BETWEEN 100 AND 140",
666
620
  config,
667
- errors={
668
- "Missing restriction for table: products column: price value: [80, 150]"
669
- },
670
- fix="SELECT prod_id, prod_name, price FROM products WHERE (price BETWEEN 200 AND 300) AND price BETWEEN 80 AND 150",
671
621
  cnn=cnn,
672
- data=[], # No products in this range
622
+ data=[(1, "Product A", 120.0)], # No products in this range
673
623
  )
674
624
 
675
- def test_group_by_having_price_avg(self, cnn, config):
625
+ def test_group_by_having_price(self, cnn, config):
676
626
  verify_sql_test(
677
- "SELECT prod_category, AVG(price) AS avg_price "
627
+ "SELECT prod_category, price "
678
628
  "FROM products "
679
- "GROUP BY prod_category "
680
- "HAVING AVG(price) > 100",
629
+ "WHERE price > 100 "
630
+ "GROUP BY prod_category",
631
+ config,
632
+ {"Missing restriction for table: products column: price value: [80, 150]"},
633
+ "SELECT prod_category, price FROM products WHERE (price > 100) AND price BETWEEN 80 AND 150 GROUP BY prod_category",
634
+ cnn=cnn,
635
+ data=[("CategoryA", 120)], # Products in CategoryA with price > 100
636
+ )
637
+
638
+
639
+ class TestSQLOrderRestrictions:
640
+
641
+ @pytest.fixture(scope="class")
642
+ def cnn(self):
643
+ with sqlite3.connect(":memory:") as conn:
644
+ # Create orders table
645
+ conn.execute(
646
+ """
647
+ CREATE TABLE orders (
648
+ id INTEGER,
649
+ product_name TEXT,
650
+ account_id INTEGER
651
+ )"""
652
+ )
653
+ # Insert sample data into orders table
654
+
655
+ conn.execute(
656
+ """INSERT INTO orders (id, product_name, account_id)
657
+ VALUES
658
+ (1, 'Product A', 123),
659
+ (2, 'Product B', 124),
660
+ (3, "Product C", 125)
661
+ """
662
+ )
663
+
664
+ yield conn
665
+
666
+ @pytest.fixture(scope="class")
667
+ def config(self):
668
+ # Assuming self._ALLOWED_ACCOUNT_ID is defined
669
+ self._ALLOWED_ACCOUNT_ID = 124 # Example value for the allowed account ID
670
+ self._TABLE_NAME = "orders" # Define table name
671
+
672
+ return {
673
+ "tables": [
674
+ {
675
+ "table_name": self._TABLE_NAME,
676
+ "columns": ["id", "product_name", "account_id"],
677
+ "restrictions": [
678
+ {
679
+ "column": "account_id",
680
+ "value": [
681
+ self._ALLOWED_ACCOUNT_ID,
682
+ ],
683
+ }, # Restriction without IN
684
+ ],
685
+ }
686
+ ]
687
+ }
688
+
689
+ def test_in_operator_with_restriction_(self, config, cnn):
690
+ sql = """SELECT product_name FROM orders WHERE account_id IN (123, 124, 125)"""
691
+
692
+ # Modify the config to handle "value" as "values" just for this specific test case
693
+ for table in config["tables"]:
694
+ for restriction in table["restrictions"]:
695
+ if "value" in restriction:
696
+ # If 'value' is present, convert it to 'values'
697
+ restriction["values"] = restriction["value"]
698
+ del restriction["value"] # Remove 'value' key
699
+
700
+ # Run the verify_sql_test function with the defined SQL query and configuration
701
+ verify_sql_test(
702
+ sql,
703
+ config,
704
+ errors=set(), # No errors expected as the restriction matches the IN clause
705
+ fix=None, # No fix should be needed
706
+ cnn=cnn,
707
+ data=[("Product A",), ("Product B",), ("Product C",)],
708
+ )
709
+
710
+ def test_id_greater_than_122_should_return_error(self, config):
711
+ """Test case for ensuring that queries with id >= 123 are invalid"""
712
+
713
+ # SQL query to test
714
+ sql_query = "SELECT id, product_name FROM orders WHERE id >= 123"
715
+
716
+ # Run the verify_sql_test function to validate the query against the restrictions
717
+ res = verify_sql(sql_query, config)
718
+
719
+ # Assert that the query is not allowed (should return an error)
720
+ assert res["allowed"] is False, res
721
+
722
+ def test_id_greater_return_error(self, config, cnn):
723
+
724
+ verify_sql_test(
725
+ "SELECT id, product_name FROM orders WHERE id >= 123",
681
726
  config,
727
+ cnn=cnn,
682
728
  errors={
683
- "Missing restriction for table: products column: price value: [80, 150]"
729
+ "Missing restriction for table: orders column: account_id value: [124]"
684
730
  },
685
- fix="SELECT prod_category, AVG(price) AS avg_price FROM products WHERE price BETWEEN 80 AND 150 GROUP BY prod_category HAVING AVG(price) > 100",
686
- cnn=cnn,
687
- data=[("CategoryA", 135)], # Avg of 120 and 150 in CategoryA
731
+ fix="SELECT id, product_name FROM orders WHERE (id >= 123) AND account_id = 124",
732
+ data=[],
688
733
  )
@@ -28,7 +28,7 @@ class TestInvalidQueries:
28
28
  )"""
29
29
  )
30
30
 
31
- # Insert values into products1 table
31
+ # Insert values into products1
32
32
  conn.execute(
33
33
  "INSERT INTO products1 VALUES (324, 'prod1', 'delivered', 'granted', '27-02-2025', 'c1')"
34
34
  )
@@ -678,10 +678,6 @@ class TestMultipleRestriction:
678
678
  "SELECT id FROM products1 WHERE id IN (324)",
679
679
  config,
680
680
  cnn=cnn,
681
- errors={
682
- "Missing restriction for table: products1 column: id value: [324, 224]"
683
- },
684
- fix="SELECT id FROM products1 WHERE (id IN (324)) AND id IN (324, 224)",
685
681
  data=[["324"]],
686
682
  )
687
683
 
@@ -701,10 +697,6 @@ class TestMultipleRestriction:
701
697
  verify_sql_test(
702
698
  """SELECT id FROM products1 WHERE id IN (324, 224)""",
703
699
  config,
704
- errors={
705
- "Missing restriction for table: products1 column: id value: [324, 224]"
706
- },
707
- fix="SELECT id FROM products1 WHERE (id IN (324, 224)) AND id IN (324, 224)",
708
700
  cnn=cnn,
709
701
  data=[["324"]],
710
702
  )
@@ -713,60 +705,37 @@ class TestMultipleRestriction:
713
705
  verify_sql_test(
714
706
  """SELECT id FROM products1 WHERE id IN (324, 233)""",
715
707
  config,
716
- errors={
717
- "Missing restriction for table: products1 column: id value: [324, 224]"
718
- },
719
- fix="SELECT id FROM products1 WHERE (id IN (324, 233)) AND id IN (324, 224)",
720
708
  cnn=cnn,
721
709
  data=[["324"]],
722
710
  )
723
711
 
724
712
  def test_in_operator_with_or(self, config, cnn):
725
713
  verify_sql_test(
726
- """SELECT id FROM products1 WHERE (id IN (324, 224) OR prod_name = 'prod3')""",
714
+ """SELECT id FROM products1 WHERE id IN (324, 224) OR prod_name = 'prod3'""",
727
715
  config,
728
- cnn=cnn,
729
716
  errors={
730
717
  "Missing restriction for table: products1 column: id value: [324, 224]"
731
718
  },
732
- fix="""SELECT id FROM products1 WHERE ((id IN (324, 224) OR prod_name = 'prod3')) AND id IN (324, 224)""",
733
- data=[["324"]],
734
- )
735
-
736
- def test_not_in_operator(self, config, cnn):
737
- verify_sql_test(
738
- """SELECT id FROM products1 WHERE (NOT id IN (324, 224))""",
739
- config,
719
+ fix="SELECT id FROM products1 WHERE (id IN (324, 224) OR prod_name = 'prod3') AND "
720
+ "id IN (324, 224)",
740
721
  cnn=cnn,
741
- errors={
742
- "Missing restriction for table: products1 column: id value: [324, 224]"
743
- },
744
- fix="SELECT id FROM products1 WHERE ((NOT id IN (324, 224))) AND id IN (324, 224)",
745
- data=[],
722
+ data=[
723
+ ("324",),
724
+ ],
746
725
  )
747
726
 
748
727
  def test_in_operator_with_numeric_values(self, config, cnn):
749
728
  verify_sql_test(
750
- """SELECT id FROM products2 WHERE (id IN (324, 224) AND category IN ('electronics', 'furniture'))""",
729
+ """SELECT id FROM products2 WHERE id IN (324, 224) AND category IN ('electronics', 'furniture')""",
751
730
  config,
752
731
  cnn=cnn,
753
- errors={
754
- "Missing restriction for table: products2 column: id value: [324, 224]"
755
- },
756
- fix="SELECT id FROM products2 WHERE ((id IN (324, 224) AND category IN "
757
- "('electronics', 'furniture'))) AND id IN (324, 224)",
758
732
  data=[],
759
733
  )
760
734
 
761
735
  def test_in_operator_with_between(self, config, cnn):
762
736
  verify_sql_test(
763
- """SELECT id FROM products1 WHERE (id IN ('324', '224') AND date BETWEEN '2024-01-01' AND '2025-01-01')""",
737
+ """SELECT id FROM products1 WHERE id in (324, 224) AND date BETWEEN '2024-01-01' AND '2025-01-01' """,
764
738
  config,
765
739
  cnn=cnn,
766
- errors={
767
- "Missing restriction for table: products1 column: id value: [324, 224]"
768
- },
769
- fix="SELECT id FROM products1 WHERE ((id IN ('324', '224') AND date BETWEEN "
770
- "'2024-01-01' AND '2025-01-01')) AND id IN (324, 224)",
771
740
  data=[],
772
741
  )
File without changes
File without changes