Проблема с Informix JDBC, MONEY и десятичным разделителем в строковых литералах - PullRequest
2 голосов
/ 07 января 2010

У меня проблема с приложением JDBC, которое использует тип данных MONEY. Когда я вставляю в колонку ДЕНЬГИ:

insert into _money_test (amt) values ('123.45')

Я получил исключение:

Character to numeric conversion error

Тот же SQL работает из собственного приложения Windows, используя драйвер ODBC. Я живу в Польше, у меня есть польский язык и в моей стране запятая разделяет десятичная часть числа, поэтому я попытался:

insert into _money_test (amt) values ('123,45')

И это сработало. Я проверил, что в PreparedStatement я должен использовать разделитель точек: 123.45. И конечно я могу использовать:

insert into _money_test (amt) values (123.45)

Но некоторый код является "общим", он импортирует данные из CSV-файла, и было безопасно поместить число в строковый литерал.

Как заставить JDBC использовать DBMONEY (или просто точку) в литералах?

Моя рабочая станция - WinXP. У меня есть клиент ODBC и JDBC Informix в версии 3.50 TC5 / JC5. Я установил DBMONEY на точку:

DBMONEY=.

EDIT:

Тестовый код в Jython:

import sys
import traceback
from java.sql import DriverManager
from java.lang import Class

Class.forName("com.informix.jdbc.IfxDriver")

QUERY = "insert into _money_test (amt) values ('123.45')"

def test_money(driver, db_url, usr, passwd):
    try:
        print("\n\n%s\n--------------" % (driver))
        db = DriverManager.getConnection(db_url, usr, passwd)
        c = db.createStatement()
        c.execute("delete from _money_test")
        c.execute(QUERY)
        rs = c.executeQuery("select amt from _money_test")
        while (rs.next()):
            print('[%s]' % (rs.getString(1)))
        rs.close()
        c.close()
        db.close()
    except:
        print("there were errors!")
        s = traceback.format_exc()
        sys.stderr.write("%s\n" % (s))



print(QUERY)
test_money("com.informix.jdbc.IfxDriver", 'jdbc:informix-sqli://169.0.1.225:9088/test:informixserver=ol_225;DB_LOCALE=pl_PL.CP1250;CLIENT_LOCALE=pl_PL.CP1250;charSet=CP1250', 'informix', 'passwd')
test_money("sun.jdbc.odbc.JdbcOdbcDriver", 'jdbc:odbc:test', 'informix', 'passwd')

Результаты, когда я запускаю денежный литерал с точкой и запятой:

C:\db_examples>jython ifx_jdbc_money.py
insert into _money_test (amt) values ('123,45')


com.informix.jdbc.IfxDriver
--------------
[123.45]


sun.jdbc.odbc.JdbcOdbcDriver
--------------
there were errors!
Traceback (most recent call last):
    File "ifx_jdbc_money.py", line 16, in test_money
        c.execute(QUERY)
SQLException: java.sql.SQLException: [Informix][Informix ODBC Driver][Informix]Character to numeric conversion error


C:\db_examples>jython ifx_jdbc_money.py
insert into _money_test (amt) values ('123.45')


com.informix.jdbc.IfxDriver
--------------
there were errors!
Traceback (most recent call last):
    File "ifx_jdbc_money.py", line 16, in test_money
        c.execute(QUERY)
SQLException: java.sql.SQLException: Character to numeric conversion error



sun.jdbc.odbc.JdbcOdbcDriver
--------------
[123.45]

Ответы [ 2 ]

2 голосов
/ 07 января 2010

Документация по отображению типов данных Informix JDBC гласит следующее:

java.math.BigDecimal ДЕНЬГИ (p, s) 1

Таким образом, вам нужно использовать java.math.BigDecimal вместо java.lang.String для представления значения, PreparedStatement#setBigDecimal() для установки значения и ResultSet#getBigDecimal() чтобы получить значение.

Вы можете "преобразовать" из String в BigDecimal, просто передав его в качестве аргумента constructor . Обратный путь можно сделать, вызвав toString() метод BigDecimal.

0 голосов
/ 18 января 2010

Я решил эту проблему с помощью PreparedStatement. Я думаю, что «Ошибка преобразования символов в числовые» является ошибкой в ​​драйвере JDBC Informix.

В другой базе данных, которую я часто использую, PostgreSQL, нет разницы, если я запускаю запрос через собственный драйвер JDBC или через мост JDBC-ODBC. Я обнаружил, что PostgreSQL не принимает числовую форму 123.45. PostgreSQL принимает строковый литерал с точкой, но эта точка обрабатывается как разделитель тысяч. Единственное правильно принятое значение - строковый литерал, в котором запятая разделяет десятичную часть.

EDIT

Это можно решить, установив DBMONEY=. на стороне сервера, тогда все соединения (ODBC, JDBC) будут работать с этим параметром.

...