Skip to content

Remove template from sql service schema#156342

Draft
emontnemery wants to merge 1 commit intodevfrom
sql_adjust_service_schema
Draft

Remove template from sql service schema#156342
emontnemery wants to merge 1 commit intodevfrom
sql_adjust_service_schema

Conversation

@emontnemery
Copy link
Contributor

Proposed change

Remove template from sql service schema, fixes late review comment #150287 (comment)

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

  • This PR fixes or closes issue: fixes #
  • This PR is related to issue:
  • Link to documentation pull request:
  • Link to developer documentation pull request:
  • Link to frontend pull request:

Checklist

  • I understand the code I am submitting and can explain how it works.
  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • I have followed the perfect PR recommendations
  • The code has been formatted using Ruff (ruff format homeassistant tests)
  • Tests have been added to verify that the new code works.
  • Any generated code has been carefully reviewed for correctness and compliance with project standards.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • For the updated dependencies - a link to the changelog, or at minimum a diff between library versions is added to the PR description.

To help with the load of incoming pull requests:

Copilot AI review requested due to automatic review settings November 11, 2025 09:16
@home-assistant
Copy link

Hey there @gjohansson-ST, @dougiteixeira, mind taking a look at this pull request as it has been labeled with an integration (sql) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of sql can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign sql Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component) on the pull request.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR aims to remove template processing from the SQL service schema validation by changing the query parameter from cv.template to cv.string. However, the implementation has a critical bug that breaks template rendering in SQL queries.

Key changes:

  • Service schema now accepts plain strings instead of Template objects for queries
  • Validation function updated to handle both Template and str types via async_get_hass()
  • Query rendering step removed from service execution path

Critical issue: The query is validated (with templates rendered) but then the unrendered string is passed to SQLAlchemy for execution, breaking template support in queries.

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
homeassistant/components/sql/util.py Modified validate_sql_select to accept both Template and str types, using async_get_hass() to obtain HomeAssistant instance for string inputs; adds type ignore comment for Template.hass access
homeassistant/components/sql/services.py Changed service schema from template-based to string-based validation; removed template rendering before query execution (bug: queries with templates will now fail)

Comment on lines +52 to +53
if isinstance(value, str):
hass = async_get_hass()
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using async_get_hass() in a schema validator is problematic. Schema validation can happen in various contexts where the HomeAssistant instance may not be available in thread-local storage, which will cause async_get_hass() to raise a HomeAssistantError.

According to the Home Assistant developer documentation, async_get_hass() "should be used where it's very cumbersome or downright impossible to pass hass to the code which needs it." In this case, since the validator is called during service schema validation before the service handler receives call.hass, there's no way to pass hass directly.

However, this creates a fragile dependency on thread-local state. Consider these alternatives:

  1. Move the validation logic to the service handler where call.hass is available
  2. Accept that validation during schema processing will be limited and defer full validation to the service handler

Note: While this may work in the current service call path, it creates a tight coupling to the execution context that could break if the validation is triggered from other contexts.

Copilot uses AI. Check for mistakes.
if isinstance(value, str):
hass = async_get_hass()
else:
hass = value.hass # type: ignore[assignment]
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The # type: ignore[assignment] comment suppresses a legitimate type error. The issue is that value.hass (when value is a Template) has type HomeAssistant | None, but the type annotation declares hass: HomeAssistant without the optional.

Instead of suppressing the error, consider handling the None case explicitly:

if isinstance(value, str):
    hass = async_get_hass()
else:
    if value.hass is None:
        raise vol.Invalid("Template does not have hass instance")
    hass = value.hass

This makes the code more robust and aligns with Home Assistant's linting guidelines that discourage using # type: ignore when the underlying issue can be properly addressed.

Suggested change
hass = value.hass # type: ignore[assignment]
if value.hass is None:
raise vol.Invalid("Template does not have hass instance")
hass = value.hass

Copilot uses AI. Check for mistakes.
rendered_query = check_and_render_sql_query(call.hass, query_str)
try:
result: Result = sess.execute(generate_lambda_stmt(rendered_query))
result: Result = sess.execute(generate_lambda_stmt(query_str))
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The query string is being passed directly to generate_lambda_stmt() without rendering any Jinja2 templates it may contain. Previously, check_and_render_sql_query() was called to render templates before execution.

If the query contains template syntax like {{ states('sensor.example') }}, it will be passed as-is to SQLAlchemy, which will fail or produce incorrect results.

The query needs to be rendered before execution. You should call check_and_render_sql_query(call.hass, query_str) and use the returned rendered query:

from .util import (
    async_create_sessionmaker,
    check_and_render_sql_query,  # Re-add this import
    convert_value,
    generate_lambda_stmt,
    # ...
)

# In _execute_and_convert_query:
def _execute_and_convert_query() -> list[JsonValueType]:
    """Execute the query and return the results with converted types."""
    sess: Session = sessmaker()
    rendered_query = check_and_render_sql_query(call.hass, query_str)
    try:
        result: Result = sess.execute(generate_lambda_stmt(rendered_query))

Note that check_and_render_sql_query is defined in util.py and can handle both Template and str inputs, so this will work with the new string-based schema.

Copilot uses AI. Check for mistakes.
Comment on lines +51 to +57
hass: HomeAssistant
if isinstance(value, str):
hass = async_get_hass()
else:
hass = value.hass # type: ignore[assignment]
try:
assert value.hass
check_and_render_sql_query(value.hass, value)
check_and_render_sql_query(hass, value)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is correct. If we get a string, I don't think we should be trying to render it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's at least unnecessary, I'll rewrite so we don't do that.

@frenck frenck marked this pull request as draft November 28, 2025 10:18
@frenck
Copy link
Member

frenck commented Nov 28, 2025

Marked the PR a draft, until the above has been done/resolved.

@github-actions
Copy link

There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days.
If you are the author of this PR, please leave a comment if you want to keep it open. Also, please rebase your PR onto the latest dev branch to ensure that it's up to date with the latest changes.
Thank you for your contribution!

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

Comments