Skip to content

fix(client-engine-runtime): parameterize primitive values of Json fields - #30861

Open
lazerg wants to merge 2 commits into
prisma:v7from
lazerg:fix/issue-30859-json-primitive-params
Open

lazerg wants to merge 2 commits into
prisma:v7from
lazerg:fix/issue-30859-json-primitive-params

Conversation

@lazerg

@lazerg lazerg commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Problem

A string, number or boolean written to a Json field is never replaced by a placeholder, so the literal stays in the query plan cache key. Every distinct value compiles a new plan and adds its own cache entry. With large string payloads the cache fills up to queryPlanCacheMaxSize entries that each hold the value, which is the memory growth reported in the issue. #handlePrimitive returns early when matchesPrimitiveMask fails, and that check has no case for the Json bit, so the JSON.stringify branch below it never runs for a Json-only field.

Change

Primitives on an edge whose mask includes Json are now stringified and given a Json placeholder before the primitive type check, the same way #handleObject and #handleArray already treat objects and arrays. The gt/gte/lt/lte Json filters are left as literals, because the query compiler reads their value to pick the JSON type to compare against and panics on a placeholder there.

Tests

Unit tests in scalar-values.test.ts (with a Json field added to the fixture schema) check that a string and a number in the same Json field share one parameterized query, and that Json comparison filters keep their literal. Functional tests: a primitive values case in json-fields, and a where path gt case in 0-legacy-ports/json for postgres and mysql. The Json functional suites pass on better-sqlite3, pg and mariadb.

Fixes #30859

Summary by CodeRabbit

  • Bug Fixes
    • Fixed handling of primitive values in JSON fields so strings, numbers, decimals, and booleans retain their correct JSON types when stored.
    • Fixed JSON-path greater-than comparisons for string values so matching records can be returned correctly.
    • JSON comparison filters using greater-than or less-than operators now preserve their comparison values without converting them into query parameters.

@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Source mode: Auto
  • Repository: prisma/orm
  • Branch: v7
  • File: .coderabbit.yml
  • Commit: 97ea359
  • Layers: Repository YAML
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: e12d97dc-3cdd-451b-818b-d76fb917978f
📥 Commits

Reviewing files that changed from the base of the PR and between 168941b and a876714.

📒 Files selected for processing: 3
  • packages/client-engine-runtime/src/parameterization/parameterize-tests/scalar-values.test.ts
  • packages/client-engine-runtime/src/parameterization/parameterize.ts
  • packages/client/tests/functional/0-legacy-ports/json/tests.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

📝 Walkthrough

The parameterizer now serializes primitive values in JSON fields and registers them as JSON placeholders. It leaves values for gt, gte, lt, and lte filters unchanged. Tests cover query parameterization, JSON values, and JSON-path comparisons.

Changes: JSON primitive parameterization

Layer / File(s) Summary
Parameterize JSON primitives
packages/client-engine-runtime/src/parameterization/parameterize.ts, packages/client-engine-runtime/src/parameterization/parameterize-tests/test-fixtures.ts, packages/client-engine-runtime/src/parameterization/parameterize-tests/scalar-values.test.ts, packages/client/tests/functional/json-fields/tests.ts
The parameterizer serializes primitive values in JSON fields and registers them as Json placeholders. Tests check string and number parameterization and round-trip storage of string, integer, decimal, and boolean values.
Preserve JSON comparison filters
packages/client-engine-runtime/src/parameterization/parameterize.ts, packages/client-engine-runtime/src/parameterization/parameterize-tests/scalar-values.test.ts, packages/client/tests/functional/0-legacy-ports/json/tests.ts
The parameterizer leaves values under gt, gte, lt, and lte unchanged. Tests check that a gt filter is not parameterized and that JSON-path greater-than queries return a result for MySQL and PostgreSQL.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: aqrln

Pre-merge checks: Passed 5
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title names the main change: primitive values (strings, numbers, booleans) of Json fields are now parameterized in client-engine-runtime. The raw summary and objectives match this. The title is sp…
Linked Issues check Passed Issue #30859 requires primitive string and number values written to Json fields to use placeholders and share a cached query shape. The production change now JSON-stringifies Json-masked primitives be…
Out of Scope Changes check Passed The changes stay within issue #30859. The production change fixes primitive Json parameterization. The fixture change supports the unit test. The unit and functional tests verify cache-shape parameter…
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 5 files.
Full details: Title check

Explanation

The title names the main change: primitive values (strings, numbers, booleans) of Json fields are now parameterized in client-engine-runtime. The raw summary and objectives match this. The title is specific and does not include file lists. The commit note about keeping comparison-filter primitives literal is a supporting detail and does not conflict with the title.

Full details: Linked Issues check

Explanation

Issue #30859 requires primitive string and number values written to Json fields to use placeholders and share a cached query shape. The production change now JSON-stringifies Json-masked primitives before primitive matching and creates a Json placeholder. The unit test verifies that string and number values produce equal parameterized queries. The functional test covers string, integer, decimal, and boolean Json values. The comparison-filter exception preserves literals for gt, gte, lt, and lte, as required for query compilation, and tests cover the gt case.

Full details: Out of Scope Changes check

Explanation

The changes stay within issue #30859. The production change fixes primitive Json parameterization. The fixture change supports the unit test. The unit and functional tests verify cache-shape parameterization, Json round trips, and the comparison-filter compatibility case. No unrelated implementation or test scope is shown.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

This branch has not been deployed

No deployments
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