Uploaded image for project: 'Debezium'
  1. Debezium
  2. DBZ-9181

Non-standard number format causing NumberFormatException

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Major Major
    • 3.3.0.CR1
    • 2.7.5.Final, 3.1.3.Final
    • informix-connector
    • None
    • False
    • Hide

      None

      Show
      None
    • False
    • Moderate

      In order to make your issue reports as actionable as possible, please provide the following information, depending on the issue type.

      Bug report

      For bug reports, provide this information, please:

      What Debezium connector do you use and what version?

      • Debezium Informix Connector v2.7.4 for our project
      • Problem also still exists in most recent version (tested with 3.1.3.FINAL)

        What is the connector configuration?

      Extract ...

      {
        "name": "InformixSourceConnector",
        "config": {
          "connector.class": "io.debezium.connector.informix.InformixConnector",
          "producer.compression.type": "gzip",
          "tasks.max": "1",
          "snapshot.fetch.size": "10000", 
          "poll.interval.ms": "1000",
          "max.batch.size": "2048",
          "max.queue.size": "8192",
          "max.queue.size.in.bytes": "67108864",
          "offset.flush.interval.ms": "10000",
      
          "database.server.name":"demo",
          "database.hostname": "XXX.XXX.XXX.XXX",
          "database.port": "1526",
          "database.dbname" : "test",
          "database.user": "informix",
          "database.password": "XXXXX",
          "database.server.id": "1000",
          "topic.prefix": "tst",
          "table.include.list": "test.fx.test_table",
      
          "include.schema.changes": "true",
          "snapshot.mode": "initial",
          "snapshot.isolation.mode": "read_committed",
          "signal.enabled.channels": "source",
      
          "transforms": "route,unwrap",
      
          "transforms.route.type": "org.apache.kafka.connect.transforms.RegexRouter",
          "transforms.route.regex": "XXXXXXXX",
          "transforms.route.replacement": "XXXX",
      
          "transforms.unwrap.type": "io.debezium.transforms.ExtractNewRecordState",
          "transforms.unwrap.drop.tombstones": "true",
          "transforms.unwrap.delete.handling.mode": "rewrite",
          "transforms.unwrap.add.fields": "ts_ms",
      
          "decimal.handling.mode": "double"
      
        }
      }
      

      What is the captured database version and mode of deployment?

      (E.g. on-premises, with a specific cloud provider, etc.)

      • On-Premises
      • IBM Informix Dynamic Server Version 12.10.FC15WE
      • Problem still exists with IBM version 14

      What behavior do you expect?

      Default values in database handled correctly even when the Informix database is not using standard US settings. In particular the Informix environment variables

      • DBMONEY,
      • DBCENTURY and
      • DBDATE

      seem to cause problems.

      What behavior do you see?

      connect-1    | 2025-06-26 07:50:18,767 INFO   Informix_Server|ifxserver|streaming  Set CDCEngine's LSN to '17185435648' aka LSN(4,54f000)   [io.debezium.connector.informix.InformixStreamingChangeEventSource]
      ifxserver-1  | 2025-06-26 07:50:18.790  CDC: Log Reader starting to snoop at the REQUESTED position, LSN(4,54f000), page 0.
      ifxserver-1  | 2025-06-26 07:50:18.791  CDC: Log Reader started.  CDC session id 24117287. SQL session id 46.
      connect-1    | 2025-06-26 07:50:18,797 INFO   Informix_Server|ifxserver|streaming  Parsing default value for column 'test_col' with expression '0,0000000000'   [io.debezium.connector.informix.InformixDefaultValueConverter]
      connect-1    | 2025-06-26 07:50:18,797 WARN   Informix_Server|ifxserver|streaming  Cannot parse column default value '0,0000000000' to type '3'.  Expression evaluation is not supported.   [io.debezium.connector.informix.InformixDefaultValueConverter]
      connect-1    | java.lang.NumberFormatException: Character , is neither a decimal digit number, decimal point, nor "e" notation exponential mark.
      connect-1    | 	at java.base/java.math.BigDecimal.<init>(BigDecimal.java:608)
      connect-1    | 	at java.base/java.math.BigDecimal.<init>(BigDecimal.java:497)
      connect-1    | 	at java.base/java.math.BigDecimal.<init>(BigDecimal.java:903)
      connect-1    | 	at io.debezium.connector.informix.InformixDefaultValueConverter.lambda$numericDefaultValueMapper$5(InformixDefaultValueConverter.java:158)
      connect-1    | 	at io.debezium.connector.informix.InformixDefaultValueConverter.lambda$nullableDefaultValueMapper$3(InformixDefaultValueConverter.java:138)
      connect-1    | 	at io.debezium.connector.informix.InformixDefaultValueConverter.parseDefaultValue(InformixDefaultValueConverter.java:59)
      connect-1    | 	at io.debezium.relational.TableSchemaBuilder.lambda$parseDefaultValue$9(TableSchemaBuilder.java:505)
      connect-1    | 	at java.base/java.util.Optional.flatMap(Optional.java:289)
      connect-1    | 	at io.debezium.relational.TableSchemaBuilder.parseDefaultValue(TableSchemaBuilder.java:505)
      connect-1    | 	at io.debezium.relational.TableSchemaBuilder.addField(TableSchemaBuilder.java:439)
      connect-1    | 	at io.debezium.relational.TableSchemaBuilder.lambda$create$2(TableSchemaBuilder.java:200)
      connect-1    | 	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
      connect-1    | 	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
      connect-1    | 	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1708)
      connect-1    | 	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
      connect-1    | 	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
      connect-1    | 	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
      connect-1    | 	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
      connect-1    | 	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
      connect-1    | 	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
      connect-1    | 	at io.debezium.relational.TableSchemaBuilder.create(TableSchemaBuilder.java:198)
      connect-1    | 	at io.debezium.relational.RelationalDatabaseSchema.buildAndRegisterSchema(RelationalDatabaseSchema.java:122)
      connect-1    | 	at io.debezium.connector.informix.InformixDatabaseSchema.applySchemaChange(InformixDatabaseSchema.java:59)
      connect-1    | 	at io.debezium.pipeline.EventDispatcher$SchemaChangeEventReceiver.schemaChangeEvent(EventDispatcher.java:696)
      connect-1    | 	at io.debezium.connector.informix.InformixStreamingChangeEventSource.lambda$handleMetadata$3(InformixStreamingChangeEventSource.java:427)
      connect-1    | 	at io.debezium.pipeline.EventDispatcher.dispatchSchemaChangeEvent(EventDispatcher.java:402)
      connect-1    | 	at io.debezium.connector.informix.InformixStreamingChangeEventSource.handleMetadata(InformixStreamingChangeEventSource.java:418)
      connect-1    | 	at io.debezium.connector.informix.InformixStreamingChangeEventSource.execute(InformixStreamingChangeEventSource.java:193)
      connect-1    | 	at io.debezium.connector.informix.InformixStreamingChangeEventSource.execute(InformixStreamingChangeEventSource.java:37)
      connect-1    | 	at io.debezium.pipeline.ChangeEventSourceCoordinator.streamEvents(ChangeEventSourceCoordinator.java:322)
      connect-1    | 	at io.debezium.pipeline.ChangeEventSourceCoordinator.executeChangeEventSources(ChangeEventSourceCoordinator.java:203)
      connect-1    | 	at io.debezium.pipeline.ChangeEventSourceCoordinator.lambda$start$0(ChangeEventSourceCoordinator.java:143)
      connect-1    | 	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
      connect-1    | 	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
      connect-1    | 	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
      connect-1    | 	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
      connect-1    | 	at java.base/java.lang.Thread.run(Thread.java:1583)
      kafka-1      | 2025-06-26 07:50:19,145 - INFO  [data-plane-kafka-request-handler-3:Logging@66] - Creating topic ifxserver with configuration {} and initial partition assignment HashMap(0 -> ArrayBuffer(1))
      connect-1    | 2025-06-26 07:50:19,154 WARN   ||  [Producer clientId=connector-producer-inventory-connector-0] The metadata response from the cluster reported a recoverable issue with correlation id 4 : {ifxserver=LEADER_NOT_AVAILABLE}   [org.apache.kafka.clients.NetworkClient]
      kafka-1      | 2025-06-26 07:50:19,161 - INFO  [data-plane-kafka-request-handler-4:Logging@66] - [ReplicaFetcherManager on broker 1] Removed fetcher for partitions Set(ifxserver-0)
      

      Do you see the same behaviour using the latest released Debezium version?

      (Ideally, also verify with latest Alpha/Beta/CR version)

      Yes. Tested with Version 3.1.3.FINAL as well

      Do you have the connector logs, ideally from start till finish?

      (You might be asked later to provide DEBUG/TRACE level log)

      Yes. But issue can be reproduced easily with a patch.

      How to reproduce the issue using our tutorial deployment?

      • Clone the tutorial: 
        git clone git@github.com:debezium/debezium-examples.git
      • Apply the patch below
        The changed files are attached to this issue as well
      • cd debezium-examples/tutorial
      • export DEBEZIUM_VERSION=3.1.3.Final
      • Build docker images
        docker compose -f docker-compose-ifx.yaml build
      • Start the environment
        docker compose -f docker-compose-ifx.yaml up
      • Register the corresponding connector
        curl -i -X POST -H "Accept:application/json" -H  "Content-Type:application/json" http://localhost:8083/connectors/ -d @register-ifx.json
      % git diff                                          
      diff --git a/tutorial/debezium-ifx-init/ifxserver/Dockerfile b/tutorial/debezium-ifx-init/ifxserver/Dockerfile
      index ec9d4cd..4401f75 100644
      --- a/tutorial/debezium-ifx-init/ifxserver/Dockerfile
      +++ b/tutorial/debezium-ifx-init/ifxserver/Dockerfile
      @@ -5,7 +5,11 @@ LABEL maintainer="Debezium Community"
       ADD --chown=informix:informix --chmod=775 informix_post_init.sh /opt/ibm/config
       ADD --chown=informix:informix --chmod=775 inventory.sql /opt/ibm/informix/etc
       
      -ENV DBDATE Y4MD-
      +#ENV DBDATE Y4MD-
      +ENV DBMONEY ,
      +ENV DBCENTURY C
      +ENV DBDATE DMY4.
      +
       ENV TYPE oltp
       ENV SIZE medium
       ENV LICENSE accept
      diff --git a/tutorial/debezium-ifx-init/ifxserver/inventory.sql b/tutorial/debezium-ifx-init/ifxserver/inventory.sql
      index de70238..669cc66 100644
      --- a/tutorial/debezium-ifx-init/ifxserver/inventory.sql
      +++ b/tutorial/debezium-ifx-init/ifxserver/inventory.sql
      @@ -73,3 +73,8 @@ INSERT INTO informix.orders(order_date,purchaser,quantity,product_id)
         VALUES ('2016-02-19', 1002, 2, 106);
       INSERT INTO informix.orders(order_date,purchaser,quantity,product_id)
         VALUES ('2016-02-21', 1003, 1, 107);
      +
      +CREATE TABLE informix.table_default_test (
      +  id SERIAL(1001) NOT NULL PRIMARY KEY,
      +  test_col decimal(16) default 0.0000000000000000
      +);
      

      Feature request or enhancement

      For feature requests or enhancements, provide this information, please:

      Which use case/requirement will be addressed by the proposed feature?

      <Your answer>

      Implementation ideas (optional)

      At the moment I see two possible ways to improve the code

      1. The following change handling of default values in "InformixDevaultValueConverter.java" fixes the issue in a brute force way but is not flexible enough for all situations.

      Diff is from version 2.7.4

      +++ b/src/main/java/io/debezium/connector/informix/InformixDefaultValueConverter.java
      @@ -155,7 +155,8 @@ public class InformixDefaultValueConverter implements DefaultValueConverter {
       
           public static DefaultValueMapper numericDefaultValueMapper() {
               return (column, value) -> {
      -            BigDecimal decimal = new BigDecimal(value);
      +            // BigDecimal decimal = new BigDecimal(value);
      +            BigDecimal decimal = new BigDecimal(value.replace(",", "."));
                   return column.scale().<Number> map(decimal::setScale).orElseGet(decimal::toBigIntegerExact);
               };
           }
      

      2. Allow parameters to be passed to the database that would change the values returned.

      • Class "InformixConnection" currently uses the variable URL_PATTERN to create the template for the JDBC connection string. From my research it should be possible to pass parameters to the database using key-value-pairs added to the connection string to change the behavior of the data returned.

        1. Debezium_Connect_Error.log
          183 kB
          Michael Fuchs
        2. Dockerfile
          0.4 kB
          Michael Fuchs
        3. inventory.sql
          3 kB
          Michael Fuchs

              Unassigned Unassigned
              michael.fuchs@sla.de Michael Fuchs (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

                Created:
                Updated:
                Resolved: