Skip to content

[backend:fix] fix interactive and portal publish PythonUDF MCDB-100138 - #138

Open
KarishS2 wants to merge 3 commits into
mainfrom
MCDB-100138/karish-chaudhary/udf-publish-fixes
Open

KarishS2 wants to merge 3 commits into
mainfrom
MCDB-100138/karish-chaudhary/udf-publish-fixes

Conversation

@KarishS2

@KarishS2 KarishS2 commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Interactive run_udf_app() used CREATE OR REPLACE by name, so a notebook session could steal a published Python UDF SQL function onto /pythonudfs/<session>/interactive/. After the session died the function failed.

Interactive registration now reads SHOW CREATE, then only creates a missing name or replaces a function that already points at this session URL. Published and other-session functions are left alone. The _test suffix is unchanged. CLI / mmap still use register_functions(replace=True).

Pairs with Helios #28074 (Portal republish / idle-wake repair).

Test Plan

  • Added unit tests for SHOW CREATE URL parse and interactive create / replace / refuse
  • Staging test with Helios #28074: publish a UDF, run run_udf_app() on the same names, confirm published SQL is unchanged, then republish and confirm the published URL is restored

Note

Medium Risk
Changes how interactive sessions mutate MCDB external function definitions; misclassification could leave wrong URLs or block registration, but published UDFs are explicitly protected.

Overview
Interactive notebook Python UDF registration no longer overwrites published SQL functions. run_udf_app() now calls register_interactive_functions() instead of register_functions(replace=True), and logs which SQL names were registered.

For each endpoint, registration uses SHOW CREATE FUNCTION to read the existing MANAGED/SERVICE URL (via new function_url helpers). It creates missing names, replaces only when the function already points at this session’s URL, and fails if a name is bound to a published or other-session URL. Stale functions still tied to this session URL but no longer in the app are dropped. _locate_app_functions uses the same URL parsing for matching.

CLI / non-interactive paths still use register_functions(replace=True). Unit tests cover URL extraction, classification, and interactive register preflight / stale cleanup.

Reviewed by Cursor Bugbot for commit ab113be. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Registration can leave partial or stale SQL definitions pointing to an unavailable endpoint.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
What changed in this PR

Prevents interactive notebook sessions from overwriting published or other-session Python UDF registrations.

Changes:

  • Adds service URL parsing and ownership classification.
  • Introduces ownership-aware interactive registration.
  • Adds unit tests and registration logging.
File Description
singlestoredb/​functions/​ext/​function_url.py Adds URL parsing and classification helpers.
singlestoredb/​functions/​ext/​asgi.py Implements interactive registration safeguards.
singlestoredb/​apps/​_python_udfs.py Uses the new registration path and logs names.
singlestoredb/​tests/​test_function_url.py Tests URL parsing and ownership classification.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +1839 to +1843
def register_interactive_functions(
self,
*connection_args: Any,
**connection_kwargs: Any,
) -> None:
Comment thread singlestoredb/functions/ext/asgi.py Outdated
Comment on lines +1852 to +1875
for _key, (_endpoint, info) in self.endpoints.items():
sig = info['signature']
sql_name = sig['name']
existing = self._show_create_service_url(cur, sql_name)
try:
action = classify_interactive_registration(
existing, self.url,
)
except ValueError as exc:
raise RuntimeError(
f'Cannot register SQL function `{sql_name}`: {exc}',
) from exc
create_sqls = [
signature_to_sql(
sig,
url=self.url,
data_format=self.data_format,
app_mode=self.app_mode,
replace=(action == 'replace'),
database=self.function_database or None,
),
]
for stmt in create_sqls:
cur.execute(stmt)

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 18a98b1. Configure here.

args = getattr(exc, 'args', ())
if args and args[0] == ER.FUNCTION_NOT_DEFINED:
return True
return False

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing-function error code too narrow

High Severity

is_function_not_defined only treats ER.FUNCTION_NOT_DEFINED (1128) as “name is missing.” SHOW CREATE FUNCTION on an absent stored or external function commonly raises ER.SP_DOES_NOT_EXIST (1305) instead. _show_create_service_url then re-raises, so first-time interactive registration never reaches CREATE.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 18a98b1. Configure here.

@kesmit13 kesmit13 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't see anything obviously incorrect. Just make sure to address the AI reviews.

This branch was successfully deployed

1 active deployment
Base — ab113bec Deployed Sep 29, 2026 by KarishS2 via test-coverage #528
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants