question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

MySQL has issues joining on IDs with variation in capitalization

See original GitHub issue

Bug description

I have a set of IDs that should be treated without case sensitivity, as the default behavior for MySQL works. However, I have issues joining items which vary in capitalization.

How to reproduce

Full reproduction:

Initialization
  1. Check out my example repo on this branch
  2. Navigate to typescript/script
  3. yarn install
  4. Install a .env file with a DB_URL variable which points to a working MySQL database
  5. yarn run prisma db push
  6. yarn run prisma db seed
Joining from varied case FKs to case insensitive PKs
  1. yarn run items
  2. Expect that both Items with ID and id values for otherItemId map to the same OtherItem with the PK of ID.
  3. Observe that only the exact match correctly joins.
  4. Observe that the raw sql SELECT * FROM Item INNER JOIN OtherItem ON Item.otherItemId = OtherItem.id exhibits the correct behavior of joining both rows.
Joining from case insensitive PKs to varied case FKs
  1. yarn run otherItems
  2. Observe the client panic

Expected behavior

MySQL is case insensitive by default and should therefore join on IDs with varying capitalization.

Prisma information

This is also included in the repro commit described above, with the diff here.

Schema
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url = env("DB_URL")
}

model Item {
  id Int @default(autoincrement()) @id
  otherItemId    String
  otherItem OtherItem? @relation(fields: [otherItemId], references: [id])
  @@index([otherItemId]) 
}

model OtherItem {
  id String @id
  item Item[] 
}
Seed
await prisma.otherItem.createMany({
    data: [
        {id: 'ID', value: Math.random()}
    ]
})
await prisma.item.createMany({
    data: [
        /**
         * Correctly has relationship with its associated Item
         */
        {otherItemId: 'ID'},

        /**
         * Does not have an associated Item.
         */
        {otherItemId: 'id'}
    ]
});
Item query
/**
 * Only the case sensitive ID match joins with the OtherItem table. The other is null.
 */
const items = await prisma.item.findMany({
  include: {
    otherItem: true
  }
});

/**
 * Querying raw correctly joins both items.
 */
const rawResult = await prisma.$queryRaw`SELECT * FROM Item INNER JOIN OtherItem ON Item.otherItemId = OtherItem.id`;
OtherItem query
// Causes a client panic
const otherItems = await prisma.otherItem.findMany({
  include: {
    item: true
  }
})

Environment & setup

  • OS: OSX 11.6
  • Database: MySQL 8.0.27
  • Node.js version: v16.13.0

Prisma Version

prisma : 3.7.0 @prisma/client : 3.7.0 Current platform : darwin Query Engine (Node-API) : libquery-engine 8746e055198f517658c08a0c426c7eec87f5a85f (at node_modules/@prisma/engines/libquery_engine-darwin.dylib.node) Migration Engine : migration-engine-cli 8746e055198f517658c08a0c426c7eec87f5a85f (at node_modules/@prisma/engines/migration-engine-darwin) Introspection Engine : introspection-core 8746e055198f517658c08a0c426c7eec87f5a85f (at node_modules/@prisma/engines/introspection-engine-darwin) Format Binary : prisma-fmt 8746e055198f517658c08a0c426c7eec87f5a85f (at node_modules/@prisma/engines/prisma-fmt-darwin) Default Engines Hash : 8746e055198f517658c08a0c426c7eec87f5a85f Studio : 0.445.0

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
chrbalacommented, Jan 10, 2022

MySQL is case insensitive by default and should therefore join on IDs with varying capitalization.

Do you maybe have a MySQL documentation link for this behavior?

Yes. This doc describes collation types. utf8mb4_unicode_ci is the collation type which Prisma created all my tables with by default. utf8mb4_unicode_ci is a case insensitive collation type, which is denoted by the ci at the end of the name.

0reactions
pimeyscommented, Sep 9, 2022

Doesn’t matter which collation is in use, SQL Server and MySQL can join with a case-insensitive strings, and with strings with whitespace in the both ends on one of the sides, but missing from the other. Reproduction:

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

model Item {
  id          Int        @id @default(autoincrement())
  otherItemId String
  otherItem   OtherItem? @relation(fields: [otherItemId], references: [id])

  @@index([otherItemId])
}

model OtherItem {
  id   String @id
  item Item[]
}
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient({
  log: ['query', 'info', 'warn', 'error'],
})

async function main() {
  await prisma.item.deleteMany()
  await prisma.otherItem.deleteMany()

  await prisma.otherItem.createMany({ data: [ { id: 'ID' } ] })

  await prisma.item.createMany({
	 data: [ {otherItemId: 'ID'}, {otherItemId: 'id'} ]
  })

  const items = await prisma.item.findMany({
    include: {
      otherItem: true
    }
  })

  console.log(items)
}

main()
  .then(async () => {
    await prisma.$disconnect()
  })
  .catch(async (e) => {
    console.error(e)
    await prisma.$disconnect()
    process.exit(1)
  })

debug logs

  prisma:tryLoadEnv  Environment variables loaded from /prisma-11032/.env +0ms
  prisma:tryLoadEnv  Environment variables loaded from /prisma-11032/.env +2ms
  prisma:client  dirname /prisma-11032/node_modules/.prisma/client +0ms
  prisma:client  relativePath ../../../prisma +0ms
  prisma:client  cwd /prisma-11032/prisma +0ms
  prisma:client  clientVersion 4.3.1 +1ms
  prisma:client  clientEngineType library +0ms
  prisma:client:libraryEngine  internalSetup +0ms
  prisma:client:libraryEngine:loader  Searching for Query Engine Library in /prisma-11032/node_modules/.prisma/client +0ms
  prisma:client:libraryEngine:loader  loadEngine using /prisma-11032/node_modules/.prisma/client/libquery_engine-debian-openssl-1.1.x.so.node +0ms
  prisma:client  Prisma Client call: +46ms
  prisma:client  prisma.item.deleteMany(undefined) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  mutation {
  deleteManyItem {
    count
  }
}
 +0ms
  prisma:client:libraryEngine  sending request, this.libraryStarted: false +47ms
  prisma:client:libraryEngine  library starting +0ms
prisma:info Starting a mysql pool with 33 connections.
  prisma:client:libraryEngine  library started +2ms
prisma:query BEGIN
prisma:query SELECT `prisma`.`Item`.`id` FROM `prisma`.`Item` WHERE 1=1 /* traceparent=00-00-00-00 */
prisma:query SELECT `prisma`.`Item`.`id` FROM `prisma`.`Item` WHERE 1=1 /* traceparent=00-00-00-00 */
prisma:query DELETE FROM `prisma`.`Item` WHERE `prisma`.`Item`.`id` IN (?,?) /* traceparent=00-00-00-00 */
prisma:query COMMIT
  prisma:client  Prisma Client call: +37ms
  prisma:client  prisma.otherItem.deleteMany(undefined) +0ms
  prisma:client  Generated request: +0ms
  prisma:client  mutation {
  deleteManyOtherItem {
    count
  }
}
 +0ms
  prisma:client:libraryEngine  sending request, this.libraryStarted: true +34ms
prisma:query BEGIN
prisma:query SELECT `prisma`.`OtherItem`.`id` FROM `prisma`.`OtherItem` WHERE 1=1 /* traceparent=00-00-00-00 */
prisma:query SELECT `prisma`.`OtherItem`.`id` FROM `prisma`.`OtherItem` WHERE 1=1 /* traceparent=00-00-00-00 */
prisma:query DELETE FROM `prisma`.`OtherItem` WHERE `prisma`.`OtherItem`.`id` IN (?) /* traceparent=00-00-00-00 */
prisma:query COMMIT
  prisma:client  Prisma Client call: +22ms
  prisma:client  prisma.otherItem.createMany({
  data: [
    {
      id: 'ID'
    }
  ]
}) +1ms
  prisma:client  Generated request: +0ms
  prisma:client  mutation {
  createManyOtherItem(data: [
    {
      id: "ID"
    }
  ]) {
    count
  }
}
 +0ms
  prisma:client:libraryEngine  sending request, this.libraryStarted: true +23ms
prisma:query BEGIN
prisma:query INSERT INTO `prisma`.`OtherItem` (`id`) VALUES (?) /* traceparent=00-00-00-00 */
prisma:query COMMIT
  prisma:client  Prisma Client call: +18ms
  prisma:client  prisma.item.createMany({
  data: [
    {
      otherItemId: 'ID'
    },
    {
      otherItemId: 'id'
    }
  ]
}) +1ms
  prisma:client  Generated request: +0ms
  prisma:client  mutation {
  createManyItem(data: [
    {
      otherItemId: "ID"
    },
    {
      otherItemId: "id"
    }
  ]) {
    count
  }
}
 +0ms
  prisma:client:libraryEngine  sending request, this.libraryStarted: true +19ms
prisma:query BEGIN
prisma:query INSERT INTO `prisma`.`Item` (`otherItemId`) VALUES (?), (?) /* traceparent=00-00-00-00 */
prisma:query COMMIT
  prisma:client  Prisma Client call: +23ms
  prisma:client  prisma.item.findMany({
  include: {
    otherItem: true
  }
}) +1ms
  prisma:client  Generated request: +0ms
  prisma:client  query {
  findManyItem {
    id
    otherItemId
    otherItem {
      id
    }
  }
}
 +0ms
  prisma:client:libraryEngine  sending request, this.libraryStarted: true +24ms
prisma:query SELECT `prisma`.`Item`.`id`, `prisma`.`Item`.`otherItemId` FROM `prisma`.`Item` WHERE 1=1 /* traceparent=00-00-00-00 */
prisma:query SELECT `prisma`.`OtherItem`.`id` FROM `prisma`.`OtherItem` WHERE `prisma`.`OtherItem`.`id` IN (?,?)
[
  { id: 5, otherItemId: 'ID', otherItem: { id: 'ID' } },
  { id: 6, otherItemId: 'id', otherItem: null }
]
  prisma:client:libraryEngine  library stopping +7ms
  prisma:client:libraryEngine  library stopped +0ms
  prisma:client:libraryEngine:exitHooks  exit event received: beforeExit +0ms
  prisma:client:libraryEngine:exitHooks  exit event received: exit +0ms
Read more comments on GitHub >

github_iconTop Results From Across the Web

20356: Names containing UPPERCASES get LOWERCASE'd
MySQL Bugs: #20356: Names containing UPPERCASES get LOWERCASE'd. Description: On Windows when creating a VIEW having UPPERCASE(s) it its name ...
Read more >
mysql - Capitalize first letter of each word, in existing table
This will only fix the first word, not the entire string. Eg "fred jones" => "Fred jones". Should be going for "Fred Jones"....
Read more >
How can we capitalize only first letter of a string with the help ...
Actually, there is no single function in MySQL to capitalize only first letter of the string. We need to use nesting of functions...
Read more >
MySQL 5.7 UPDATE slow due to not using index
We don't use multi-table JOINS , but UPDATE … WHERE `userid` IN (<list of 10k ids>);; We currently "only" have the issue on...
Read more >
MySQL By Examples for Beginners
The SQL keywords and commands are NOT case-sensitive. For clarity, they are shown in uppercase. The names or identifiers (database names, table names,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found