SeaQL / SeaQL/sea-orm

Last Insert ID unpackaging fails for MySQL when using Default values for autoincremented key

Open
#662 5 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
9.9k
Forks
734
Avg merge
6h 36m
Merged PRs (30d)
8

Description

Description

When inserting a value in a table with several primary keys and using the default value for an auto-incremented one, the insert fails.

Known to be reproducible with MySQL.

Steps to Reproduce

  1. First create a simple database having a table with several one primary key, one being auto-incremented
- MySQL dump 10.13  Distrib 8.0.28, for Linux (x86_64)
--
-- Host: localhost    Database: sea
-- ------------------------------------------------------
-- Server version	8.0.28-0ubuntu0.20.04.3

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `GAME`
--

DROP TABLE IF EXISTS `GAME`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `GAME` (
  `id` int NOT NULL AUTO_INCREMENT,
  `home_team_id` int NOT NULL,
  `away_team_id` int NOT NULL,
  PRIMARY KEY (`id`,`home_team_id`,`away_team_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2022-04-04 19:18:04

Table schema :

schema

  1. Create a new cargo project and generate the entities with the sea-orm-cli
cargo new sea_orm_issue
cd sea_orm_issue
sea-orm-cli generate entity -o src/entities/

Entity generated :

//! SeaORM Entity. Generated by sea-orm-codegen 0.7.0

use sea_orm::entity::prelude::*;

#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "GAME")]
pub struct Model {
    #[sea_orm(primary_key)]
    pub id: i32,
    #[sea_orm(primary_key, auto_increment = false)]
    pub home_team_id: i32,
    #[sea_orm(primary_key, auto_increment = false)]
    pub away_team_id: i32,
}

#[derive(Copy, Clone, Debug, EnumIter)]
pub enum Relation {}

impl RelationTrait for Relation {
    fn def(&self) -> RelationDef {
        panic!("No RelationDef")
    }
}

impl ActiveModelBehavior for ActiveModel {}
  1. Add the following dependencies in Cargo.toml :
[dependencies]
sea-orm = { version ="0.7" , features = ["runtime-async-std-native-tls", "sqlx-mysql"]}
tokio = { version = "1.17.0", features = ["full"] }
env_logger = "0.9.0"
  1. Create a simple main to insert your entity :
pub mod entities;
use entities::{game};
use sea_orm::{entity::*, error::*, Database, DbConn};

#[tokio::main]
async fn main() -> Result<(), DbErr> {
    env_logger::init();
    let db: DbConn = Database::connect("mysql://sea_usr:password@dbhost:3306/sea").await.unwrap();
    let new_game = game::ActiveModel {
        home_team_id: Set(1),
        away_team_id: Set(2),
        ..Default::default()
    };
    new_game.insert(&db).await?;
    Ok(())
}
  1. Run it
cargo r
  1. And it should throw the following error (detailed log.txt attached)
cargo r
    Finished dev [unoptimized + debuginfo] target(s) in 0.21s
     Running `target/debug/sea-orm-issue-multiple-pk`
Error: Exec("Fail to unpack last_insert_id")

Let's note that :

  • the issue doesn't occur when we have a single primary key in the table
  • the entity is persisted despite the error being thrown
Expected Behavior

The entity should be inserted in the table, and no error should be thrown.

Actual Behavior

The entity is inserted in the table, but an error is thrown

Reproduces How Often

On every insert for a mysql database

Versions

  • MySQL v8
  • Rust 1.57
  • Sea-ORM 0.7.0
  • Rust 1.57

Additional Information

A sample project will be shared

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the generated entities/game model and the main insertion shown in the report, then reproduce the failure using MySQL 8 and the attached log.txt details. Trace the insert and last-insert-ID handling until the composite-primary-key case is isolated. Done means the row is inserted without an error, matching the expected behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
mysql, rust
Domain
backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.