Skip to content

fix(orm): split jsonb_build_object calls exceeding PostgreSQL 100-arg limit#2554

Merged
ymc9 merged 1 commit intodevfrom
fix/issue-2524-pg-jsonb-100-arg-limit
Apr 3, 2026
Merged

fix(orm): split jsonb_build_object calls exceeding PostgreSQL 100-arg limit#2554
ymc9 merged 1 commit intodevfrom
fix/issue-2524-pg-jsonb-100-arg-limit

Conversation

@ymc9
Copy link
Copy Markdown
Member

@ymc9 ymc9 commented Apr 3, 2026

Summary

  • PostgreSQL's FUNC_MAX_ARGS limit is 100. jsonb_build_object takes key-value pairs, so a relation with 51+ columns produces 102+ arguments and crashes with error code 54023
  • Fix chunks the entries into groups of ≤50 pairs and concatenates the resulting jsonb objects with the || operator
  • Adds a regression test that includes a relation with 51 columns on PostgreSQL

Fixes #2524

Test plan

  • Regression test tests/regression/test/issue-2524.test.ts passes against a real PostgreSQL instance
  • Existing PostgreSQL dialect tests continue to pass (relations with ≤50 columns are unaffected — the fast path returns a single jsonb_build_object call as before)

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Resolved an issue where certain complex database queries would fail to execute in PostgreSQL environments.
  • Tests

    • Added regression test coverage for complex query scenarios.

… limit

When including a nested relation with 51+ columns, the generated
jsonb_build_object call would exceed PostgreSQL's FUNC_MAX_ARGS limit
of 100 (error code 54023). Fix by chunking the key-value pairs into
groups of 50 and concatenating the resulting jsonb objects with ||.

Fixes #2524

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

📝 Walkthrough

Walkthrough

Modified buildJsonObject in the PostgreSQL dialect to split large jsonb_build_object calls into chunks of up to 50 key/value pairs, merging results with the || operator to work around PostgreSQL's 100-argument function limit. Added a regression test validating the fix handles tables with 51+ columns.

Changes

Cohort / File(s) Summary
PostgreSQL jsonb Chunking
packages/orm/src/client/crud/dialects/postgresql.ts
Modified buildJsonObject to chunk argument lists when exceeding 50 key/value pairs, building separate jsonb_build_object() calls and merging with || operator to respect FUNC_MAX_ARGS limit.
Regression Test for Issue #2524
tests/regression/test/issue-2524.test.ts
New Vitest regression test validating fix for PostgreSQL error 54023 by creating a schema with 51-column table in a nested relation, executing findMany with include, and asserting successful query execution.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Poem

🐰 Hops excitedly
A chunky problem? No despair!
Split those pairs with SQL care,
Fifty at a time we bound,
With || merges, JSON's sound!
PostgreSQL limits? We hop right through! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main fix: splitting jsonb_build_object calls to avoid exceeding PostgreSQL's 100-argument limit.
Linked Issues check ✅ Passed The code changes implement the core fix by chunking jsonb_build_object arguments into groups of ≤50 pairs and concatenating with the || operator, with a regression test validating the fix for 51-column relations.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing issue #2524; the implementation modifies only the PostgreSQL dialect handler and adds a targeted regression test.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-2524-pg-jsonb-100-arg-limit

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Apr 3, 2026

Claude finished @ymc9's task —— View job


Code Review: PostgreSQL jsonb_build_object 100-argument limit fix

Summary: This PR successfully addresses PostgreSQL's FUNC_MAX_ARGS limit of 100 by chunking jsonb_build_object calls and concatenating them with the || operator. The implementation is clean and well-tested.

Code Quality & Best Practices

Strong Points:

  • Clean implementation: The fix is well-contained in the buildJsonObject method at postgresql.ts:337-357
  • Good constant naming: MAX_PAIRS = 50 clearly indicates the constraint (100 args ÷ 2 = 50 key-value pairs)
  • Helpful comments: Explains the PostgreSQL limitation and chunking strategy
  • Maintains backward compatibility: Relations with ≤50 columns use the original fast path
  • Follows existing patterns: Uses established Kysely expression building patterns

Minor Suggestion:
Consider extracting the chunk building logic for improved readability:

private buildJsonObjectChunk(entries: [string, Expression<unknown>][]) {
    return this.eb.fn('jsonb_build_object', entries.flatMap(([k, v]) => [sql.lit(k), v]));
}

Correctness & Bug Analysis

The implementation looks correct:

  • Proper chunking: entries.slice(i, i + MAX_PAIRS) correctly partitions the entries
  • Correct concatenation: Using || operator for JSONB merge is the right PostgreSQL approach
  • Type safety: Return type AliasableExpression<unknown> is appropriate
  • Edge case handling: Works correctly for exactly 50 pairs (boundary condition)

Performance Considerations

Positive aspects:

  • Minimal overhead: For ≤50 columns, performance is identical to before
  • Efficient chunking: reduce() creates a linear chain of || operations
  • No runtime checks: The chunking logic runs at query build time, not execution time

Performance is optimal for this constraint. The alternative (multiple queries) would be significantly slower.

Security

No security concerns identified:

  • Uses parameterized queries via sql.lit(k) and expression values
  • No dynamic SQL string construction
  • Follows existing security patterns in the codebase

Test Coverage

Excellent test coverage in issue-2524.test.ts:

  • Precise reproduction: 51 columns = 102 args, exceeding the 100-arg limit
  • Real-world scenario: Tests actual relation inclusion with include: { opportunities: true }
  • Error prevention: Verifies the specific PostgreSQL error 54023 doesn't occur
  • Comprehensive validation: Checks both result length and nested data structure

Test quality: The test model with 51 columns precisely targets the edge case and validates the fix works end-to-end.

📝 Minor Recommendations

  1. Consider adding a unit test directly for the buildJsonObject method to test the chunking logic in isolation
  2. Documentation: Consider adding a brief note in the method's JSDoc about the PostgreSQL limitation

Overall Assessment

This is a high-quality fix that elegantly solves a real PostgreSQL limitation. The implementation is:

  • Correct: Properly handles the 100-argument constraint
  • Performant: No overhead for common cases, minimal overhead for large relations
  • Well-tested: Comprehensive regression test validates the fix
  • Maintainable: Clean, documented code following established patterns
  • Backward compatible: No breaking changes

Recommendation: Approve - This PR is ready for merge.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/regression/test/issue-2524.test.ts (1)

90-92: Strengthen the assertion to verify fields beyond the first 50 pairs are returned.

Current checks confirm row counts, but not that chunk-merged JSON contains tail fields. Add a check for col51 to guard against partial-object regressions.

Proposed test enhancement
         expect(result).toHaveLength(1);
         expect(result[0].opportunities).toHaveLength(1);
+        expect(result[0].opportunities[0].col51).toBe('');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/regression/test/issue-2524.test.ts` around lines 90 - 92, Add an
assertion that verifies the merged JSON includes fields beyond the first 50
pairs by checking for the presence/value of col51: after the existing
expectations on result and result[0].opportunities, assert that
result[0].opportunities[0].row.col51 is defined (or equals the expected value)
so the test fails if the tail fields are omitted; update the test block that
uses result/opportunities/row to include this new check.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/regression/test/issue-2524.test.ts`:
- Around line 90-92: Add an assertion that verifies the merged JSON includes
fields beyond the first 50 pairs by checking for the presence/value of col51:
after the existing expectations on result and result[0].opportunities, assert
that result[0].opportunities[0].row.col51 is defined (or equals the expected
value) so the test fails if the tail fields are omitted; update the test block
that uses result/opportunities/row to include this new check.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f06906f1-3d3c-4fe4-bc6e-2ae6a20f5533

📥 Commits

Reviewing files that changed from the base of the PR and between dbb3474 and 66cc8e0.

📒 Files selected for processing (2)
  • packages/orm/src/client/crud/dialects/postgresql.ts
  • tests/regression/test/issue-2524.test.ts

@ymc9 ymc9 merged commit 744c760 into dev Apr 3, 2026
9 checks passed
@ymc9 ymc9 deleted the fix/issue-2524-pg-jsonb-100-arg-limit branch April 3, 2026 22:49
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.

PostgreSQL error 54023 (cannot pass more than 100 arguments to a function) on wide nested relations

1 participant