test(mssql): add reproduction test for batch insert type inconsistency by yangbobo2021 · Pull Request #29418 · prisma/prisma · GitHub
Skip to content

test(mssql): add reproduction test for batch insert type inconsistency#29418

Open
yangbobo2021 wants to merge 1 commit intoprisma:mainfrom
yangbobo2021:issue-29354-batch-insert-reproduction
Open

test(mssql): add reproduction test for batch insert type inconsistency#29418
yangbobo2021 wants to merge 1 commit intoprisma:mainfrom
yangbobo2021:issue-29354-batch-insert-reproduction

Conversation

@yangbobo2021
Copy link
Copy Markdown

This PR adds a reproduction test for #29354.

Problem

When performing batch inserts with Float field values, the mssql adapter produces inconsistent parameter types depending on the value range:

  • Values within int32 range → SQL `int`
  • Values exceeding int32 range → SQL `nvarchar`

Root Cause

`packages/adapter-mssql/src/mssql.ts:56` calls `req.input()` without an explicit SQL type:
```typescript
req.input(`P${i + 1}`, mapArg(query.args[i], query.argTypes[i]))
```

This allows the mssql package to auto-detect types based on values, causing type inconsistency in batch operations.

Test Case

The test demonstrates that with values `[450000000, 3850000000, 1600000000]`:

  • `450000000` → `int` (within int32 range)
  • `3850000000` → `nvarchar` (exceeds int32 max: 2147483647)
  • `1600000000` → `int` (within int32 range)

Execution

```bash
export TEST_MSSQL_URI="mssql://SA:Pr1sm4_Pr1sm4@localhost:1433/master"
pnpm --filter @prisma/adapter-mssql test issue-29354-batch-insert
```

Suggested Fix

Add explicit SQL type to `req.input()`:
```typescript
req.input(`P${i + 1}`, sql.Float, mapArg(query.args[i], query.argTypes[i]))
```

Would you like me to create a follow-up PR with the fix?

…y (issue prisma#29354)

This commit adds a test case that reproduces the root cause of issue
prisma#29354: when performing batch inserts with Float field values, the mssql
adapter parameterizes values inconsistently depending on their range.

The test verifies that when req.input() is called without an explicit
SQL type, the mssql package auto-detects types:
- Values within int32 range -> SQL int
- Values exceeding int32 range -> SQL nvarchar

This type inconsistency causes SQL Server type precedence issues in
batch insert operations.

Root cause location: packages/adapter-mssql/src/mssql.ts:56
Current code: req.input(`P${i + 1}`, mapArg(query.args[i], query.argTypes[i]))
Suggested fix: req.input(`P${i + 1}`, sql.Float, mapArg(...))

Test execution:
export TEST_MSSQL_URI="mssql://SA:Pr1sm4_Pr1sm4@localhost:1433/master"
pnpm --filter @prisma/adapter-mssql test issue-29354-batch-insert
@CLAassistant
Copy link
Copy Markdown

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 31, 2026

Summary by CodeRabbit

  • Tests
    • Added integration test coverage for MSSQL adapter batch insert operations to improve reliability and catch potential regressions.

Walkthrough

A new Vitest integration test file is added for the MSSQL adapter to reproduce Issue #29354. The test validates batch insert parameter type inconsistency by connecting to a SQL Server instance, creating a temporary table with a FLOAT column, executing parameterized batch inserts without explicit SQL types, and asserting that type inference produces inconsistent results across the batch.

Changes

Cohort / File(s) Summary
MSSQL Batch Insert Type Inconsistency Test
packages/adapter-mssql/src/issue-29354-batch-insert.test.ts
New integration test for Issue #29354 that reproduces parameter type inconsistency in batch insert operations. Includes SQL Server connection setup, temporary table creation, parameterized batch insert execution with type inference logic, and assertions on type consistency across parameters.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: adding a reproduction test for batch insert type inconsistency in the mssql adapter.
Description check ✅ Passed The description clearly relates to the changeset, providing context about the issue, root cause, test case details, and execution instructions that directly correspond to the test file added.
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 unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

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.

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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/adapter-mssql/src/issue-29354-batch-insert.test.ts`:
- Around line 112-141: The simulated type-detection block (detectedTypes,
INT32_MAX, hasInconsistentTypes, uniqueTypes derived from testValues) is
illustrative only and doesn't inspect mssql internals; update the test by adding
a brief clarifying comment above this block that the primary verification is the
actual batch insert behavior (the subsequent insert attempt/assertions) and that
the detectedTypes logic is only for human-readable illustration of the expected
mismatch rather than a real assertion of mssql parameter types.
- Around line 162-170: The verification query and console.log should be guarded
when the batch insert fails: detect whether the insert try/catch (the block that
catches the batch insert error at the referenced catch) recorded a failure
(e.g., set a boolean like insertSucceeded) and only run the SELECT/console.log
of result.recordset.map(r => r.maxIndividualLoss) if insertSucceeded is true;
otherwise skip the SELECT and log a concise message indicating the insert failed
so the test output is clear. Ensure you reference the same pool variable and the
Issue29354Test table name when implementing the guard.
- Around line 57-62: The test body calls test.skip() conditionally, which is
misuse; instead remove the test.skip() call inside the async test and simply
early-return when the env var is missing (or declare the test as skipped at
definition time using test.skip with the same title), i.e., inside the test
handler for "should reproduce parameter type inconsistency in batch insert"
check process.env.TEST_MSSQL_URI and if falsy do a plain return (or move the
condition to use test.skip('should reproduce parameter type inconsistency in
batch insert') before the test is defined) so you stop executing but do not
invoke test.skip() mid-test.
- Around line 58-75: The test reads testMssqlUri but then uses a hardcoded
config, so either parse TEST_MSSQL_URI into the sql.config used by the test or
explicitly make the env var only a run-flag and document that; update the code
around the testMssqlUri variable and the config object so that if TEST_MSSQL_URI
is present you parse it (host, port, user, password, database, options/pool) and
populate the config, otherwise fall back to the existing hardcoded values, or
alternatively add a clear comment and rename testMssqlUri to something like
RUN_MSSQL_TEST to reflect it is only a flag. Ensure the parsing logic handles
typical mssql connection strings/URLs and populates the same config keys
referenced in the test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1126532f-d9ff-4270-9a3c-4502c52dde4e

📥 Commits

Reviewing files that changed from the base of the PR and between 5fece0a and 1e3a9d0.

📒 Files selected for processing (1)
  • packages/adapter-mssql/src/issue-29354-batch-insert.test.ts

Comment on lines +57 to +62
test('should reproduce parameter type inconsistency in batch insert', async () => {
const testMssqlUri = process.env.TEST_MSSQL_URI
if (!testMssqlUri) {
test.skip()
return
}
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.

⚠️ Potential issue | 🟡 Minor

Incorrect usage of test.skip() inside test body.

In Vitest, test.skip() is meant to define a skipped test at declaration time, not for conditional skipping inside a test body. Calling it mid-test may cause unexpected behavior. The return statement mitigates this, but the test.skip() call itself is problematic.

Suggested fix: Use early return or skipIf pattern

Option 1 - Simple early return (preferred for this case):

  test('should reproduce parameter type inconsistency in batch insert', async () => {
    const testMssqlUri = process.env.TEST_MSSQL_URI
    if (!testMssqlUri) {
-     test.skip()
+     console.log('Skipping: TEST_MSSQL_URI not set')
      return
    }

Option 2 - Use describe.skipIf at the describe block level:

-describe('Issue `#29354`: Batch Insert Type Inconsistency', () => {
+describe.skipIf(!process.env.TEST_MSSQL_URI)('Issue `#29354`: Batch Insert Type Inconsistency', () => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test('should reproduce parameter type inconsistency in batch insert', async () => {
const testMssqlUri = process.env.TEST_MSSQL_URI
if (!testMssqlUri) {
test.skip()
return
}
test('should reproduce parameter type inconsistency in batch insert', async () => {
const testMssqlUri = process.env.TEST_MSSQL_URI
if (!testMssqlUri) {
console.log('Skipping: TEST_MSSQL_URI not set')
return
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-mssql/src/issue-29354-batch-insert.test.ts` around lines 57
- 62, The test body calls test.skip() conditionally, which is misuse; instead
remove the test.skip() call inside the async test and simply early-return when
the env var is missing (or declare the test as skipped at definition time using
test.skip with the same title), i.e., inside the test handler for "should
reproduce parameter type inconsistency in batch insert" check
process.env.TEST_MSSQL_URI and if falsy do a plain return (or move the condition
to use test.skip('should reproduce parameter type inconsistency in batch
insert') before the test is defined) so you stop executing but do not invoke
test.skip() mid-test.

Comment on lines +58 to +75
const testMssqlUri = process.env.TEST_MSSQL_URI
if (!testMssqlUri) {
test.skip()
return
}

const config: sql.config = {
server: 'localhost',
port: 1433,
user: 'SA',
password: 'Pr1sm4_Pr1sm4',
database: 'master',
options: {
enableArithAbort: false,
trustServerCertificate: true,
},
pool: { max: 1 },
}
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.

⚠️ Potential issue | 🟠 Major

TEST_MSSQL_URI is checked but never used; config is hardcoded.

The test checks for TEST_MSSQL_URI to determine whether to run, but then ignores it entirely and uses hardcoded connection parameters. This is misleading—if someone sets a different URI (e.g., different host, port, or credentials), the test will ignore their configuration and potentially fail or connect to the wrong server.

Either parse the URI to extract connection parameters, or document that the env var is only a "run this test" flag and the connection details are fixed.

Suggested fix: Parse the URI or clarify intent

Option 1 - Parse the URI:

  test('should reproduce parameter type inconsistency in batch insert', async () => {
    const testMssqlUri = process.env.TEST_MSSQL_URI
    if (!testMssqlUri) {
      console.log('Skipping: TEST_MSSQL_URI not set')
      return
    }

-   const config: sql.config = {
-     server: 'localhost',
-     port: 1433,
-     user: 'SA',
-     password: 'Pr1sm4_Pr1sm4',
-     database: 'master',
-     options: {
-       enableArithAbort: false,
-       trustServerCertificate: true,
-     },
-     pool: { max: 1 },
-   }
+   const url = new URL(testMssqlUri)
+   const config: sql.config = {
+     server: url.hostname,
+     port: parseInt(url.port, 10) || 1433,
+     user: decodeURIComponent(url.username),
+     password: decodeURIComponent(url.password),
+     database: url.pathname.slice(1) || 'master',
+     options: {
+       enableArithAbort: false,
+       trustServerCertificate: true,
+     },
+     pool: { max: 1 },
+   }

Option 2 - Clarify the env var is just a flag:

+   // Note: TEST_MSSQL_URI is used only as a flag to enable this test.
+   // Connection uses fixed localhost config for reproducibility.
    const config: sql.config = {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const testMssqlUri = process.env.TEST_MSSQL_URI
if (!testMssqlUri) {
test.skip()
return
}
const config: sql.config = {
server: 'localhost',
port: 1433,
user: 'SA',
password: 'Pr1sm4_Pr1sm4',
database: 'master',
options: {
enableArithAbort: false,
trustServerCertificate: true,
},
pool: { max: 1 },
}
const testMssqlUri = process.env.TEST_MSSQL_URI
if (!testMssqlUri) {
test.skip()
return
}
const url = new URL(testMssqlUri)
const config: sql.config = {
server: url.hostname,
port: parseInt(url.port, 10) || 1433,
user: decodeURIComponent(url.username),
password: decodeURIComponent(url.password),
database: url.pathname.slice(1) || 'master',
options: {
enableArithAbort: false,
trustServerCertificate: true,
},
pool: { max: 1 },
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-mssql/src/issue-29354-batch-insert.test.ts` around lines 58
- 75, The test reads testMssqlUri but then uses a hardcoded config, so either
parse TEST_MSSQL_URI into the sql.config used by the test or explicitly make the
env var only a run-flag and document that; update the code around the
testMssqlUri variable and the config object so that if TEST_MSSQL_URI is present
you parse it (host, port, user, password, database, options/pool) and populate
the config, otherwise fall back to the existing hardcoded values, or
alternatively add a clear comment and rename testMssqlUri to something like
RUN_MSSQL_TEST to reflect it is only a flag. Ensure the parsing logic handles
typical mssql connection strings/URLs and populates the same config keys
referenced in the test.

Comment on lines +112 to +141
// STEP 4: Verify parameter types (THE ROOT CAUSE)
// mssql package doesn't expose parameter types directly, so we infer from behavior
console.log('Parameter inference:')

const INT32_MAX = 2147483647
const detectedTypes = testValues.map((value) => {
if (typeof value === 'number' && value <= INT32_MAX && value >= -INT32_MAX - 1) {
return 'int'
} else {
return 'nvarchar'
}
})

detectedTypes.forEach((type, index) => {
console.log(` @P${index + 1}: ${type} (value: ${testValues[index]})`)
})

// STEP 5: Verify BUG - parameter types are INCONSISTENT
const uniqueTypes = new Set(detectedTypes)
const hasInconsistentTypes = uniqueTypes.size > 1

console.log('\nResult:')
if (hasInconsistentTypes) {
console.log(' ❌ BUG CONFIRMED: Parameter types are INCONSISTENT')
console.log(` ❌ Types detected: ${Array.from(uniqueTypes).join(', ')}`)
console.log(' ❌ This causes SQL Server type precedence issues in batch insert')
} else {
console.log(' ✅ Parameter types are consistent')
}

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.

🧹 Nitpick | 🔵 Trivial

Type detection is simulated, not verified from mssql internals.

The test simulates what mssql's auto-detection should do based on int32 range checks, but doesn't actually verify the types that mssql assigns to parameters. The assertion expect(hasInconsistentTypes).toBe(true) passes based on the simulation logic, not on actual mssql behavior.

This is acknowledged in the comments, and the actual insert attempt (lines 152-160) does provide behavioral evidence. Consider adding a comment clarifying that the primary verification is whether the insert succeeds/fails, and the simulated type detection is illustrative.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-mssql/src/issue-29354-batch-insert.test.ts` around lines 112
- 141, The simulated type-detection block (detectedTypes, INT32_MAX,
hasInconsistentTypes, uniqueTypes derived from testValues) is illustrative only
and doesn't inspect mssql internals; update the test by adding a brief
clarifying comment above this block that the primary verification is the actual
batch insert behavior (the subsequent insert attempt/assertions) and that the
detectedTypes logic is only for human-readable illustration of the expected
mismatch rather than a real assertion of mssql parameter types.

Comment on lines +162 to +170
// STEP 7: Verify inserted values
const result = await pool.request().query('SELECT maxIndividualLoss FROM Issue29354Test ORDER BY id')
console.log(
'\nInserted values:',
result.recordset.map((r: any) => r.maxIndividualLoss),
)

// STEP 8: Clean up
await pool.request().query('DROP TABLE Issue29354Test')
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.

🧹 Nitpick | 🔵 Trivial

Consider guarding the verification query when insert fails.

If the batch insert fails (caught at lines 157-160), the verification query at line 163 will return an empty recordset, and result.recordset.map(...) will produce an empty array. This works but could be confusing when reviewing test output. Consider skipping verification or adding context when the insert fails.

Optional: Add conditional logging
      } catch (error: any) {
        console.log(`\n❌ Batch insert failed: ${error.message}`)
        console.log('   This demonstrates the type inconsistency issue')
+       // Skip verification when insert fails
+       await pool.request().query('DROP TABLE Issue29354Test')
+       expect(hasInconsistentTypes).toBe(true)
+       return
      }

      // STEP 7: Verify inserted values
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/adapter-mssql/src/issue-29354-batch-insert.test.ts` around lines 162
- 170, The verification query and console.log should be guarded when the batch
insert fails: detect whether the insert try/catch (the block that catches the
batch insert error at the referenced catch) recorded a failure (e.g., set a
boolean like insertSucceeded) and only run the SELECT/console.log of
result.recordset.map(r => r.maxIndividualLoss) if insertSucceeded is true;
otherwise skip the SELECT and log a concise message indicating the insert failed
so the test output is clear. Ensure you reference the same pool variable and the
Issue29354Test table name when implementing the guard.

Comment on lines +133 to +140
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.

we should avoid spamming console.log from tests, this should just have an concise and meaningful failing assertion

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