eclipse-vertx/vertx-sql-client

Unable to insert to database (mariadb) after DB version upgrade

yujietan opened this issue · 2 comments

Questions

Do not use this issue tracker to ask questions, instead use one of these channels. Questions will likely be closed without notice.

Version

implementation(enforcedPlatform("io.quarkus:quarkus-universe-bom:3.1.2.Final"))
 implementation("io.quarkus:quarkus-kotlin")
 implementation("io.quarkus:quarkus-jackson")
 implementation("io.quarkus:quarkus-hibernate-reactive-panache")
 implementation("io.quarkus:quarkus-reactive-mysql-client")
 implementation("io.quarkus:quarkus-hibernate-validator")
 testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.1")
 testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.1")
 testImplementation("io.quarkus:quarkus-junit5")

Context

quarkusio/quarkus#34464

Do you have a reproducer?

Unable to provide enterprise mariadb with maxscale to reproduce the issue

  • Link to github project/gist

Steps to reproduce

Hi , we tried building a reproducer but was not able to find any mariabdb image for 10.6.12-8 Enteprise

So we created the java and kotlin class required to replicate the issue

We did it using quarkus version 3.1.2.FINAL (tried with 2.16.6.FINAL the version we are using same error)

Sorrry for not uploading this as a reproducer project. Blocked by corporate network :(

Gradle Config

build.gradle

plugins {
    kotlin("jvm")
    id("java-library")
    id("io.quarkus")
}

allprojects {
    group = "com.trial.demo"
    version = "1.0.0-SNAPSHOT"
}

dependencies {
    implementation(enforcedPlatform("io.quarkus:quarkus-universe-bom:3.1.2.Final"))
    implementation("io.quarkus:quarkus-kotlin")
    implementation("io.quarkus:quarkus-jackson")
    implementation("io.quarkus:quarkus-hibernate-reactive-panache")
    implementation("io.quarkus:quarkus-reactive-mysql-client")
    implementation("io.quarkus:quarkus-hibernate-validator")
    
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.1")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.1")
    testImplementation("io.quarkus:quarkus-junit5")
}

Schema Files

CustomTable.java

package com.trial.demo.entities;
import com.trial.demo.entities.mapper.HashMapConverter;
import jakarta.persistence.*;
import java.time.Instant;
import java.util.Map;

@Entity
@Table(name = "custom_table",
        uniqueConstraints = {@UniqueConstraint(name = "UNIQUE_ACTION_MESSAGE", columnNames = {"two", "one", "ten"})})
public class CustomTable {

    public CustomTable() {
    }

    @Id
    @SequenceGenerator(
            name="custom_table_mock_seq",
            sequenceName = "custom_table_seq",
            allocationSize = 1
    )
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "custom_table_mock_seq")
    private Long id;

    @Column(name = "one", updatable = false, nullable = false)
    private int one;

    @Column(name = "two", updatable = false, nullable = false)
    private String two;

    private String three;
    private String four;
    private String five;
    private String six;
    private Instant ten;
    private Instant zero;
    private int seven;
    private String eight;
    private String nine;

    @Convert(converter = HashMapConverter.class)
    private Map<String, String> eleven;

    public Long getId() {
        return id;
    }

    public int getOne() {
        return one;
    }

    public void setOne(int one) {
        this.one = one;
    }

    public String getThree() {
        return three;
    }

    public void setThree(String three) {
        this.three = three;
    }

    public String getFour() {
        return four;
    }

    public void setFour(String four) {
        this.four = four;
    }

    public String getFive() {
        return five;
    }

    public void setFive(String five) {
        this.five = five;
    }

    public String getSix() {
        return six;
    }

    public void setSix(String six) {
        this.six = six;
    }

    public Instant getTen() {
        return ten;
    }

    public void setTen(Instant ten) {
        this.ten = ten;
    }

    public Instant getZero() {
        return zero;
    }

    public void setZero(Instant zero) {
        this.zero = zero;
    }

    public int getSeven() {
        return seven;
    }

    public void setSeven(int seven) {
        this.seven = seven;
    }

    public String getEight() {
        return eight;
    }

    public void setEight(String eight) {
        this.eight = eight;
    }

    public String getNine() {
        return nine;
    }

    public void setNine(String nine) {
        this.nine = nine;
    }

    public Map<String, String> getEleven() {
        return eleven;
    }

    public void setEleven(Map<String, String> eleven) {
        this.eleven = eleven;
    }

    public String getTwo() {
        return two;
    }

    public void setTwo(String two) {
        this.two = two;
    }

}

HashMapConverter.java

package com.trial.demo.entities.mapper;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.persistence.AttributeConverter;

import java.util.Map;

@ApplicationScoped
public class HashMapConverter implements AttributeConverter<Map<String,String>, String> {

    @Override
    public String convertToDatabaseColumn(Map<String, String> attribute) {
        if(attribute == null){
            return null;
        }
        String dataInDbFormat = null;
        ObjectMapper om = new ObjectMapper();
        try{
            dataInDbFormat = om.writeValueAsString(attribute);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return dataInDbFormat;
    }

    @Override
    public Map<String, String> convertToEntityAttribute(String dbData) {
        if(dbData == null){
            return null;
        }
        Map dataMap = null;
        ObjectMapper om = new ObjectMapper();
        try{
            dataMap = om.readValue(dbData, Map.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return dataMap;
    }
}

DAO Classes

CustomTableRepository.kt

package com.trial.demo

import com.trial.demo.entities.CustomTable
import io.quarkus.hibernate.reactive.panache.PanacheRepository
import io.quarkus.hibernate.reactive.panache.common.runtime.ReactiveTransactional
import io.smallrye.mutiny.Uni
import jakarta.enterprise.context.ApplicationScoped


@ApplicationScoped
class CustomTableRepository : PanacheRepository<CustomTable> {

    companion object {
        fun String.toPanacheSQL(): String = "#$this"
    }

    @ReactiveTransactional
    internal fun addDataToMariaDb(data: List<CustomTable>): Uni<Void> {
        return this.persist(data)
    }
}

Unit Test Class For Replicating the Issue

SqlErrorTest.java

package com.trial.demo

import com.trial.demo.entities.CustomTable
import io.quarkus.hibernate.reactive.panache.Panache
import io.quarkus.hibernate.reactive.panache.Panache.flush
import io.quarkus.test.junit.QuarkusTest
import io.quarkus.vertx.VertxContextSupport
import jakarta.inject.Inject
import org.hibernate.reactive.mutiny.Mutiny.SessionFactory
import org.junit.jupiter.api.Test
import java.time.LocalDateTime
import java.time.ZoneOffset

@QuarkusTest
class SqlErrorTest {

    @Inject
    lateinit var sessionFactory: SessionFactory

    @Inject
    lateinit var customTableRepository: CustomTableRepository

    fun generateTestData(): List<CustomTable> {
        var firstData = CustomTable()
        var secondData = CustomTable()
        firstData.one = 1
        firstData.two = "HAPPY_2"
        firstData.three = "HAPPY_3"
        firstData.four = "HAPPY_4"
        firstData.five = "HAPPY_5"
        firstData.six = "HAPPY_6"
        firstData.seven = 0
        firstData.eight = "HAPPY_8"
        firstData.nine = "HAPPY_9"
        firstData.ten = LocalDateTime.now().toInstant(ZoneOffset.UTC)
        firstData.zero = LocalDateTime.now().toInstant(ZoneOffset.UTC)
        firstData.eleven = mapOf(
            Pair("1", "1"),
            Pair("2", "2"),
            Pair("10","{\"\$aa-aa_aa_aa\":\"123\",\"\$bb-bb_bbb\":\"1a2b3c\",\"@cc-cc-8\":\"aaa_bbb_ccc=ddd\",\"@ee-ee_ee-3\":\"a[3]=ee_ee\",\"\$dd-dd\":\"1234\",\"\$ff-ff_aa\":\"-1\",\"\$gg-gg\":\"gtg\",\"@dd-dd-10\":\"ff_ff_ff_dd=6\",\"\$zz-be\":\"344.41\",\"\$hh-hh_hh\":\"1.1.0\",\"\$tt-yy\":\"16.77\",\"@pop-pp-3\":\"ff_dd_ff=/a/b/c\",\"@aa-aa-7\":\"aa_aa_aa=aa\",\"\$aa-aa_aa\":\"/aa/aa/aa/aa/aa/aa/aa.aa\",\"\$aar-aa\":\"1\",\"@aa-aal-2\":\"aa_aa=/aa/aa_aa\",\"\$aa-aa_aa\":\"1\",\"\$aa-aa_aa\":\"11\",\"\$aa-aa\":\"0\",\"@bb-bb-6\":\"bb_bb_bb=/bb/bb/bb\",\"\$br-bb_bbt\":\"0\",\"\$bb-bu_bbt\":\"1\",\"\$br-pbt_by\":\"0\",\"@bay-abr_mb-0\":\"bb\",\"\$bb-bb\":\"bb_bb\",\"@bby-bal-11\":\"bb_bb_bb=bb\",\"@bb-bb-5\":\"bb_bb_bb=/bb/bb_bb/bb\",\"@bb-bb-4\":\"bb_bb_bb=/bb/bb/bb\",\"@array-global-1\":\"bb=bb\",\"\$bbr-bbd_bb\":\"bb\",\"\$bb-bb_bb\":\"bb-bb_bb-133abc-123\",\"@bb-bb_bb-2\":\"bb[2]=bb\",\"\$bb-bbl_bb_bb\":\"0\",\"\$bb-bb_bb\":\"bb\",\"@bb-bb-0\":\"bbL\",\"\$bb-bb_bbb\":\"0\",\"\$bb-bb\":\"bb\",\"\$bb-bb_bb\":\"0\",\"\$bb\":\"21\",\"@bb-bb_bb-1\":\"bb[1]=bb\",\"\$bb-bbb_bbb\":\"0\",\"\$bbb-bb\":\"b\",\"\$bb-bb_bb\":\"134\",\"\$gg-gge_lg\":\"0\",\"\$ggr-gt\":\"62cac\",\"@gg-gggl-9\":\"gg_gg_gg=gg\",\"\$gg-gg_gg\":\"0\",\"\$gg-egg_ggd\":\"/gg/gg/gg\"}")
        )

        secondData.one = 2
        secondData.two = "HAPPY_2"
        secondData.three = "HAPPY_3"
        secondData.four = "HAPPY_4"
        secondData.five = "HAPPY_5"
        secondData.six = "HAPPY_6"
        secondData.seven = 1
        secondData.eight = "HAPPY_8"
        secondData.nine = "HAPPY_9"
        secondData.ten = LocalDateTime.now().toInstant(ZoneOffset.UTC)
        secondData.zero = LocalDateTime.now().toInstant(ZoneOffset.UTC)
        secondData.eleven = mapOf(
            Pair("3", "3"),
            Pair("4", "4"),
            Pair("5", "!@#$%^&*()_"),
            Pair("6", "=-098~\"765`432")
        )

        return mutableListOf(firstData, secondData)
    }


    /**
     *  Test Will Fail Due To SQL Syntax Error
     */
    @Test
    fun addDataWithStatelessTransaction_1() {
        var listToAdd = generateTestData()
        sessionFactory.withStatelessTransaction { session ->
            session.insertAll(*listToAdd.toTypedArray())
        }.await().indefinitely()
    }

    /**
     *  Test Will Fail Due To SQL Syntax Error
     */
    @Test
    fun addDataWithStatelessTransaction_2() {
        var listToAdd = generateTestData()
        sessionFactory.withStatelessSession { session ->
            session.withTransaction { tx ->
                tx.markForRollback()
                session.insertAll(*listToAdd.toTypedArray())
            }
        }.await().indefinitely()
    }

    /**
     *  Test Will Pass Because No Transaction Is Used
     */
    @Test
    fun addDataWithoutTransaction() {
        var listToAdd = generateTestData()
        sessionFactory.withStatelessSession { session ->
            session.insertAll(*listToAdd.toTypedArray())
        }.await().indefinitely()

    }

    /**
     *  Test Will Fail Due To SQL Syntax Error
     */
    @Test
    fun addDataUsingPanache(){
        var listToAdd = generateTestData()
        VertxContextSupport.subscribeAndAwait {
            Panache.withTransaction {
                customTableRepository.persist(listToAdd)
            }
        }
    }

    /**
     *  Test Will Pass Because No Transaction Is Used
     */
    @Test
    fun addDataUsingPanacheWithoutTransaction(){
        var listToAdd = generateTestData()
        listToAdd[0].two = "SAD"
        listToAdd[1].two = "SAD"
        VertxContextSupport.subscribeAndAwait {
            Panache.withSession {
                customTableRepository.persist(listToAdd).flatMap { flush() }
            }
        }
    }

}

DB Table DDL

CREATE SEQUENCE custom_table_seq START WITH 1 INCREMENT BY 1 NOCYCLE;
CREATE TABLE `custom_table` (
  `id` bigint(20) NOT NULL DEFAULT nextval(`custom_table_seq`),
  `one` int(11) unsigned NOT NULL,
  `two` varchar(50) NOT NULL,
  `three` varchar(100) DEFAULT NULL,
  `four` varchar(100) DEFAULT NULL,
  `five` text DEFAULT NULL,
  `six` varchar(100) DEFAULT NULL,
  `ten` datetime DEFAULT NULL,
  `zero` datetime DEFAULT NULL,
  `seven` int(11) DEFAULT NULL,
  `eight` varchar(30) DEFAULT NULL,
  `nine` varchar(30) DEFAULT NULL,
  `eleven` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `UNIQUE_ACTION_MESSAGE` (`one`,`two`,`ten`),
  KEY `idx_env` (`one`) USING BTREE,
  KEY `idx_startTime_desc` (`ten`) USING BTREE
)

Extra

  • Anything that can be relevant such as OS version, JVM version

Hi closing issue. Turns out the db server config is different. The one where is not working has ANSI_QUOTES enabled.. Thus failing with syntax error when inserting

Thank you for letting us know