Skip to content

Clean up SND script and migrate to PostgreSQL#1112

Open
labkey-adam wants to merge 9 commits intorelease26.3-SNAPSHOTfrom
26.3_fb_snd_script
Open

Clean up SND script and migrate to PostgreSQL#1112
labkey-adam wants to merge 9 commits intorelease26.3-SNAPSHOTfrom
26.3_fb_snd_script

Conversation

@labkey-adam
Copy link
Copy Markdown
Contributor

Rationale

We want the SND module to support PostgreSQL

@labkey-adam
Copy link
Copy Markdown
Contributor Author

labkey-adam commented Apr 6, 2026

Here's a summary of every translation decision that Claude made when converting the SQL Server SND script to PostgreSQL:


SQL Server → PostgreSQL Translation Notes

Type mappings

┌───────────────────────────────────────────────────┬─────────────────────────────────────────────┐
│ SQL Server │ PostgreSQL │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ NVARCHAR(n) │ VARCHAR(n) │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ NVARCHAR(MAX) │ TEXT │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ DATETIME │ TIMESTAMP │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ BIT │ BOOLEAN │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ BIT NOT NULL DEFAULT 0 │ BOOLEAN NOT NULL DEFAULT FALSE │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ BIT NOT NULL DEFAULT 1 │ BOOLEAN NOT NULL DEFAULT TRUE │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ UNIQUEIDENTIFIER NOT NULL DEFAULT newid()/NEWID() │ ENTITYID NOT NULL DEFAULT gen_random_uuid() │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ UNIQUEIDENTIFIER (nullable) │ ENTITYID │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ INTEGER IDENTITY / INT IDENTITY(1,1) │ SERIAL │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ date │ DATE │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ int │ INTEGER │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ LSIDType / LsidType │ LSIDType (same custom domain) │
├───────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ ENTITYID, USERID │ unchanged (LabKey custom domains) │
└───────────────────────────────────────────────────┴─────────────────────────────────────────────┘

Syntax changes

  • Removed all GO batch separators (not valid in PostgreSQL).
  • Removed NONCLUSTERED / CLUSTERED index keywords — PostgreSQL has no clustered index concept; all indexes are created
    as plain CREATE INDEX or CREATE UNIQUE INDEX.
  • Removed WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ...) index storage options.
  • String concatenation + → ||.
  • SPACE(n) → REPEAT(' ', n).
  • CONVERT(VARCHAR(MAX), expr) → expr::VARCHAR.
  • TOP(1) → LIMIT 1.
  • EXEC core.fn_dropifexists → SELECT core.fn_dropifexists (not needed here since this is a fresh install script with
    no pre-existing objects).

Functions (fGetSuperPkg, fGetProjectItems)

  • SQL Server inline TVF (RETURNS TABLE AS RETURN (...)) → PostgreSQL CREATE OR REPLACE FUNCTION ... RETURNS TABLE
    (...) LANGUAGE sql AS $$ ... $$.
  • WITH ... AS CTE → WITH RECURSIVE ... AS (required in PostgreSQL even when the query is recursive).
  • Return column types explicitly declared.
  • ROW_NUMBER() OVER (...) in the recursive CTE term — PostgreSQL does not permit window functions in the recursive
    member of WITH RECURSIVE. Replaced with COALESCE(sp.SortOrder, 0)::VARCHAR as the path component. This preserves the
    ordering semantics of the original (path segments are zero-padded sort-order values rather than row numbers), and a
    comment in the file explains why.

Function fGetAllSuperPkgs

  • The SQL Server cursor loop (CURSOR LOCAL FOR ... FETCH ... WHILE ... INSERT INTO) is replaced with a single CROSS
    JOIN LATERAL against snd.fGetSuperPkg, which is idiomatic PostgreSQL and far more efficient than a procedural loop.
  • Corrected the column types in the return table declaration (the original SQL Server script had several wrong types:
    SuperPkgPath INTEGER, Required INTEGER, Active INTEGER, Repeatable INTEGER).

Trigger (ti_after_events)

  • SQL Server FOR INSERT AS ... UPDATE ... FROM inserted (statement-level, set-based) → PostgreSQL row-level BEFORE
    INSERT trigger.
  • The trigger logic is split into a trigger function (snd.ti_after_events_fn() RETURNS trigger) and a CREATE TRIGGER
    statement (FOR EACH ROW EXECUTE PROCEDURE).
  • Using BEFORE INSERT instead of AFTER INSERT means NEW.QcState can be set directly before the row is written,
    avoiding the extra UPDATE that the SQL Server version required.

@labkey-adam labkey-adam self-assigned this Apr 7, 2026
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.

1 participant