Skip to content

PostgreSQL UDF Support - #4240

Merged
bharadwaj-aditya merged 1 commit into
GoogleCloudPlatform:mainfrom
c2nes:pg-udf
Oct 27, 2026
Merged

bharadwaj-aditya merged 1 commit into
GoogleCloudPlatform:mainfrom
c2nes:pg-udf

Conversation

@c2nes

@c2nes c2nes commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Adding support for UDFs in the PostgreSQL dialect.

Note, this PR is based on the previously reviewed #3325.

This PR has been rebased, review comments addressed, and a few test failures addressed.

@c2nes
c2nes requested a review from a team as a code owner September 9, 2026 16:40
@google-cla

google-cla Bot commented Sep 9, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces support for User-Defined Functions (UDFs) within the PostgreSQL dialect for Spanner Dataflow templates. It enables the export and import of PostgreSQL UDFs by mapping determinism levels to volatility keywords and enhancing parameter parsing to handle quoted identifiers and default values. These changes ensure consistency and compatibility when migrating or exporting Spanner databases using the PostgreSQL dialect.

Highlights

  • PostgreSQL UDF Support: Added full support for User-Defined Functions (UDFs) in the PostgreSQL dialect for Spanner Dataflow templates.
  • Determinism Mapping: Implemented mapping for spannerDeterminism to PostgreSQL volatility keywords (IMMUTABLE, STABLE, VOLATILE).
  • Parameter Parsing: Enhanced UDF parameter parsing to correctly handle quoted identifiers and default values in PostgreSQL.
  • Information Schema Integration: Updated the InformationSchemaScanner to extract PostgreSQL UDF metadata, including determinism and parameter details.
  • Testing: Added comprehensive unit and integration tests to verify end-to-end export and import workflows for PostgreSQL UDFs.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request adds support for User-Defined Functions (UDFs) in the PostgreSQL dialect for Cloud Spanner, including metadata extraction, Avro schema conversion, and SQL generation. The review feedback highlights critical improvements to the parsing logic in UdfParameter.parse, such as fixing a regex bug where Pattern.quote is incorrectly used inside a character class, and addressing a split-logic issue that could bypass empty default expression checks. Additionally, suggestions are made to increase robustness by trimming input parameters and handling case-insensitivity for determinism values. All comments are highly actionable and should be addressed.

Comment thread v1/src/main/java/com/google/cloud/teleport/spanner/ddl/UdfParameter.java Outdated
Comment thread v1/src/main/java/com/google/cloud/teleport/spanner/ddl/Udf.java Outdated
@codecov

codecov Bot commented Sep 9, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.50000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 56.99%. Comparing base (308eb05) to head (e2fa724).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
...ava/com/google/cloud/teleport/spanner/ddl/Udf.java 93.33% 0 Missing and 1 partial ⚠️

❗ There is a different number of reports uploaded between BASE (308eb05) and HEAD (e2fa724). Click for more details.

HEAD has 2 uploads less than BASE
Flag BASE (308eb05) HEAD (e2fa724)
3 1
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #4240      +/-   ##
============================================
- Coverage     62.66%   56.99%   -5.67%     
- Complexity     3570     7625    +4055     
============================================
  Files           607     1161     +554     
  Lines         35213    73915   +38702     
  Branches       4001     8704    +4703     
============================================
+ Hits          22067    42130   +20063     
- Misses        12026    28983   +16957     
- Partials       1120     2802    +1682     
Components Coverage Δ
spanner-templates 84.14% <ø> (+0.01%) ⬆️
spanner-import-export 72.32% <97.50%> (∅)
spanner-live-forward-migration 87.77% <ø> (+0.04%) ⬆️
spanner-live-reverse-replication 80.08% <ø> (+0.03%) ⬆️
spanner-bulk-migration 88.34% <ø> (+0.02%) ⬆️
gcs-spanner-dv 86.66% <ø> (+0.05%) ⬆️
Files with missing lines Coverage Δ
...oud/teleport/spanner/AvroSchemaToDdlConverter.java 88.44% <100.00%> (ø)
...va/com/google/cloud/teleport/spanner/AvroUtil.java 93.75% <ø> (ø)
...oud/teleport/spanner/DdlToAvroSchemaConverter.java 97.56% <100.00%> (ø)
...ava/com/google/cloud/teleport/spanner/ddl/Ddl.java 77.50% <100.00%> (ø)
...oogle/cloud/teleport/spanner/ddl/UdfParameter.java 95.91% <100.00%> (ø)
...ava/com/google/cloud/teleport/spanner/ddl/Udf.java 91.22% <93.33%> (ø)

... and 570 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

c2nes added a commit to c2nes/DataflowTemplates that referenced this pull request Sep 21, 2026
…ameter

- Trim parameter string at the start of UdfParameter.parse.
- Pass quote character directly in UdfParameter.parse regex.
- Use word boundary (?i)\s+DEFAULT\b when splitting DEFAULT expression in UdfParameter.parse.
- Match spannerDeterminism() case-insensitively in Udf.prettyPrint.
- Add unit tests in UdfParameterTest and UdfTest.

TAG=agy
CONV=f1c413a3-3f8a-43cd-8eac-9b7a2df210e0
@c2nes
c2nes force-pushed the pg-udf branch 2 times, most recently from 30389f3 to 41c7fbb Compare September 24, 2026 14:19
@c2nes
c2nes force-pushed the pg-udf branch 2 times, most recently from 2829b43 to 968c062 Compare October 23, 2026 13:53
@bharadwaj-aditya bharadwaj-aditya added the addition New feature or request label Oct 23, 2026
@bharadwaj-aditya
bharadwaj-aditya requested review from bharadwaj-aditya and darshan-sj and removed request for jsuhani-2026 and shreyakhajanchi October 23, 2026 14:56

@bharadwaj-aditya bharadwaj-aditya left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall, this looks very clean! A few minor comments on edge cases, test consolidation, and the cla/google check:

  • cla/google check: The earlier commits on this branch are authored by jacobwyant@google.com (@MnkyGns), which is causing the cla/google check to fail. Squashing the commits under @c2nes authorship (or updating commit authorship) should resolve the CLA failure.

Comment thread v1/src/main/java/com/google/cloud/teleport/spanner/ddl/UdfParameter.java Outdated
Comment thread v1/src/test/java/com/google/cloud/teleport/spanner/ImportPipelineIT.java Outdated
Comment thread v1/src/main/java/com/google/cloud/teleport/spanner/ddl/Udf.java
@c2nes

c2nes commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

@bharadwaj-aditya please take a look. I believe all your comments have been addressed and all checks have passed.

@bharadwaj-aditya bharadwaj-aditya left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@darshan-sj darshan-sj left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good overall. Left a few comments.

Comment thread v1/src/main/java/com/google/cloud/teleport/spanner/ddl/UdfParameter.java Outdated
Comment thread v1/src/test/resources/CopyDbIT-AllSchemaAndData-pg.sql
Export and import SQL user-defined functions for PostgreSQL-dialect
databases. Previously these were GoogleSQL only.

InformationSchemaScanner:
- Scan PostgreSQL routines and parameters: spanner_type,
  spanner_determinism and the qualified specific_schema.
- Skip EXTERNAL routines, e.g. change stream read_json_* functions.
- Gate UDF export on information_schema.routines.spanner_determinism
  being present.

Ddl / Udf / UdfParameter:
- Ddl.Builder.createUdf propagates the dialect.
- Udf.prettyPrint emits PostgreSQL syntax: IMMUTABLE/STABLE/VOLATILE
  from spanner_determinism (case-insensitive), SECURITY without SQL, and
  RETURN <expr> bodies.
- Never print LANGUAGE SQL for SQL UDFs. ROUTINE_BODY reports SQL, but
  neither dialect accepts LANGUAGE SQL with a SQL body. PostgreSQL has
  rejected it since --spangres_enable_remote_udf defaulted to true.
- UdfParameter.parse is dialect-aware:
  - quoted or unquoted names;
  - types containing spaces in both dialects (PostgreSQL multi-word types,
    GoogleSQL STRUCT<...>, which previously failed to import);
  - case-insensitive DEFAULT;
  - multi-line DEFAULT expressions;
  - names stored unquoted, so Ddl -> Avro -> Ddl round-trips match the
    scanner.

Avro:
- Serialize spanner_determinism as spannerUdfSpannerDeterminism.

Tests:
- Unit tests in UdfTest, UdfParameterTest, DdlTest,
  InformationSchemaScannerTest, AvroSchemaToDdlConverterTest and
  DdlToAvroSchemaConverterTest. RandomDdlGenerator now generates PG UDF
  determinism.
- InformationSchemaScannerIT covers PG UDFs, including determinism.
- ExportPipelineIT exports PG UDFs and checks the Avro properties.
- ImportPipelineIT imports pg_add and pg_multiply as part of
  testPostgresImportPipeline and calls them.
- CopyDbIT covers PG UDF parameter and return types (scalar, multi-word,
  array), mixed-case names, literal defaults, no parameters, and every
  volatility (IMMUTABLE, STABLE, VOLATILE, unspecified). The GSQL file
  adds a UDF with STRUCT and ARRAY<STRUCT> parameters.
- UDFs live in named schemas, because Cloud Spanner disallows UDFs in the
  default schema.

Based on GoogleCloudPlatform#3325 by Jacob Wyant.

TAG=agy
CONV=76f8ea42-8008-4a45-8c97-887632526bf8
@c2nes

c2nes commented Oct 26, 2026

Copy link
Copy Markdown
Contributor Author

The integration test failure was in an unrelated Neo4j test case.

@darshan-sj darshan-sj left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you!

LGTM

@bharadwaj-aditya
bharadwaj-aditya merged commit c4e24f0 into GoogleCloudPlatform:main Oct 27, 2026
26 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

addition New feature or request size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants