Skip to content

Python: Bug: SqlServerCollection renders x.tenant == None as [tenant] = ? with the string 'None' instead of IS NULL #14683

Open

Description

@BlueX888

Describe the bug

SqlServerCollection renders None in a search filter as the string literal 'None', so a filter on a nullable field can never match SQL NULL:

'lambda x: x.tenant == None'  ->  [tenant] = ?          params ['None']
'lambda x: x.tenant != None'  ->  [tenant] <> ?         params ['None']
'lambda x: x.tenant is None'  ->  NotImplementedError: Unsupported operator: <class 'ast.Is'>

The full generated query for a default_dynamic_filter_function filter with a None argument is:

SELECT [id], [tenant], [active], VECTOR_DISTANCE('cosine', [embedding], CAST(? AS VECTOR(3))) as _vector_distance_value
 FROM [dbo].[filter_records]
 WHERE [tenant] = ?
ORDER BY _vector_distance_value ASC
OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY;
parameters: ['[1.0, 0.0, 0.0]', 'None']

Root cause: _lambda_parser binds every value with command.add_parameter(str(value)) (python/semantic_kernel/connectors/sql_server.py:659-664) and the Eq/NotEq handlers (:611-616) have no NULL branch, so None becomes the varchar 'None'. Booleans are also bound as 'True'/'False' here even though _cast_value (:850) already maps them to 1/0.

To Reproduce

A self-contained script (no database needed) builds SqlServerCollection with a nullable tenant field and asks it to parse the filters above; it prints the SQL and parameter values shown above. Run from python/:

.venv/Scripts/python.exe -I repro_sqlserver_null_filter.py

The same filter path is what default_dynamic_filter_function produces when a search argument is None, so ordinary searches with an omitted nullable argument are affected.

Expected behavior

  • x.tenant == None / x.tenant is None → [tenant] IS NULL
  • x.tenant != None → [tenant] IS NOT NULL
  • x.active == True → parameter 1 (matching _cast_value)

The Postgres collection already does exactly this (fixed in #14497, covered by test_null_filter_parser); SQL Server was missed.

Platform

  • Language: Python
  • Source: main branch at 4bb64ee (2026-10-28), semantic-kernel 1.46.0
  • AI model: n/a (no model call in the reproduction)
  • OS: Windows 11

Additional context

  • Searched open and closed issues/PRs for SqlServerCollection filters and SQL Server NULL handling: no duplicate; no open PR touches sql_server.py.
  • Suggested fix: add an ast.Is/ast.IsNot branch and NULL handling in the Eq/NotEq visitors (compare with the Postgres parser), and bind booleans via _cast_value.

Reported with AI assistance (analysis and reproduction script); the reporter ran the reproduction and verified the output above.

Activity

  1. changed the title [-]Bug: SqlServerCollection renders `x.tenant == None` as `[tenant] = ?` with the string 'None' instead of IS NULL[/-] [+]Python: Bug: SqlServerCollection renders `x.tenant == None` as `[tenant] = ?` with the string 'None' instead of IS NULL[/+] on Oct 29, 2026
  2. BlueX888 commented on Oct 29, 2026

    @BlueX888
    Author

    I plan to implement this if the direction is right: add ast.Is / ast.IsNot handling and NULL branches for Eq/NotEq in SqlServerCollection._lambda_parser, mirroring the Postgres parser (#14497), and bind booleans through _cast_value so True/False become 1/0. Tests would compare generated SQL and parameters for == None, != None, is None, and booleans.

    Could this issue be assigned to me (哈基米 (@BlueX888))? Happy to adjust the approach first if you'd prefer a different fix location.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    pythonPull requests for the Python Semantic Kerneltriage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions