使用 JDBC 和 ODBC 将 TEXT 列插入 Informix 数据库的一致方法

发布于 2024-07-12 06:13:11 字数 3365 浏览 6 评论 0原文

当我尝试将一些数据插入 Informix TEXT 列时遇到问题 通过 JDBC。 在 ODBC 中,我可以像这样简单地运行 SQL:

INSERT INTO test_table (text_column) VALUES ('insert')

但这在 JDBC 中不起作用,并且出现错误:

617: A blob data type must be supplied within this context.

我搜索了此类问题并发现了 2003 年的消息:

http://groups.google.com/group/comp.databases.informix/browse_thread/thread/4dab38472e521269?ie=UTF-8&oe=utf-8&q=Informix+jdbc+%22A+ blob+data+type+must+be+supplied+within+this%22

我更改了代码以使用PreparedStatement。 现在它可以与 JDBC 一起使用, 但在 ODBC 中,当我尝试使用PreparedStatement 时,出现错误:

Error: [Informix][Informix ODBC Driver][Informix]
Illegal attempt to convert Text/Byte blob type.
[SQLCode: -608], [SQLState: S1000]

测试表是用以下内容创建的:

CREATE TABLE _text_test (id serial PRIMARY KEY, txt TEXT)

用于测试两个驱动程序的 Jython 代码:

# for Jython 2.5 invoke with --verify
# beacuse of bug: http://bugs.jython.org/issue1127

import traceback
import sys
from com.ziclix.python.sql import zxJDBC

def test_text(driver, db_url, usr, passwd):
    arr = db_url.split(':', 2)
    dbname = arr[1]
    if dbname == 'odbc':
        dbname = db_url
    print "\n\n%s\n--------------" % (dbname)
    try:
        connection = zxJDBC.connect(db_url, usr, passwd, driver)
    except:
        ex = sys.exc_info()
        s = 'Exception: %s: %s\n%s' % (ex[0], ex[1], db_url)
        print s
        return
    Errors = []
    try:
        cursor = connection.cursor()
        cursor.execute("DELETE FROM _text_test")
        try:
            cursor.execute("INSERT INTO _text_test (txt) VALUES (?)", ['prepared', ])
            print "prepared insert ok"
        except:
            ex = sys.exc_info()
            s = 'Exception in prepared insert: %s: %s\n%s\n' % (ex[0], ex[1], traceback.format_exc())
            Errors.append(s)
        try:
            cursor.execute("INSERT INTO _text_test (txt) VALUES ('normal')")
            print "insert ok"
        except:
            ex = sys.exc_info()
            s = 'Exception in insert: %s: %s\n%s' % (ex[0], ex[1], traceback.format_exc())
            Errors.append(s)
        cursor.execute("SELECT id, txt FROM _text_test")
        print "\nData:"
        for row in cursor.fetchall():
            print '[%s]\t[%s]' % (row[0], row[1])
        if Errors:
            print "\nErrors:"
            print "\n".join(Errors)
    finally:
        cursor.close()
        connection.commit()
        connection.close()


#test_varchar(driver, db_url, usr, passwd)
test_text("sun.jdbc.odbc.JdbcOdbcDriver", 'jdbc:odbc:test_db', 'usr', 'passwd')
test_text("com.informix.jdbc.IfxDriver", 'jdbc:informix-sqli://169.0.1.225:9088/test_db:informixserver=ol_225;DB_LOCALE=pl_PL.CP1250;CLIENT_LOCALE=pl_PL.CP1250;charSet=CP1250', 'usr', 'passwd')

JDBC 或 ODBC 中是否有任何设置可以使用一种版本的代码 对于两个司机?

版本信息:

  • 服务器:IBM Informix Dynamic Server 版本 11.50.TC2DE
  • 客户端:
    • ODBC 驱动程序 3.50.TC3DE
    • 适用于 IBM Informix Dynamic Server 3.50.JC3DE 的 IBM Informix JDBC 驱动程序

I have problem when I try insert some data to Informix TEXT column
via JDBC. In ODBC I can simply run SQL like this:

INSERT INTO test_table (text_column) VALUES ('insert')

but this do not work in JDBC and I got error:

617: A blob data type must be supplied within this context.

I searched for such problem and found messages from 2003:

http://groups.google.com/group/comp.databases.informix/browse_thread/thread/4dab38472e521269?ie=UTF-8&oe=utf-8&q=Informix+jdbc+%22A+blob+data+type+must+be+supplied+within+this%22

I changed my code to use PreparedStatement. Now it works with JDBC,
but in ODBC when I try using PreparedStatement I got error:

Error: [Informix][Informix ODBC Driver][Informix]
Illegal attempt to convert Text/Byte blob type.
[SQLCode: -608], [SQLState: S1000]

Test table was created with:

CREATE TABLE _text_test (id serial PRIMARY KEY, txt TEXT)

Jython code to test both drivers:

# for Jython 2.5 invoke with --verify
# beacuse of bug: http://bugs.jython.org/issue1127

import traceback
import sys
from com.ziclix.python.sql import zxJDBC

def test_text(driver, db_url, usr, passwd):
    arr = db_url.split(':', 2)
    dbname = arr[1]
    if dbname == 'odbc':
        dbname = db_url
    print "\n\n%s\n--------------" % (dbname)
    try:
        connection = zxJDBC.connect(db_url, usr, passwd, driver)
    except:
        ex = sys.exc_info()
        s = 'Exception: %s: %s\n%s' % (ex[0], ex[1], db_url)
        print s
        return
    Errors = []
    try:
        cursor = connection.cursor()
        cursor.execute("DELETE FROM _text_test")
        try:
            cursor.execute("INSERT INTO _text_test (txt) VALUES (?)", ['prepared', ])
            print "prepared insert ok"
        except:
            ex = sys.exc_info()
            s = 'Exception in prepared insert: %s: %s\n%s\n' % (ex[0], ex[1], traceback.format_exc())
            Errors.append(s)
        try:
            cursor.execute("INSERT INTO _text_test (txt) VALUES ('normal')")
            print "insert ok"
        except:
            ex = sys.exc_info()
            s = 'Exception in insert: %s: %s\n%s' % (ex[0], ex[1], traceback.format_exc())
            Errors.append(s)
        cursor.execute("SELECT id, txt FROM _text_test")
        print "\nData:"
        for row in cursor.fetchall():
            print '[%s]\t[%s]' % (row[0], row[1])
        if Errors:
            print "\nErrors:"
            print "\n".join(Errors)
    finally:
        cursor.close()
        connection.commit()
        connection.close()


#test_varchar(driver, db_url, usr, passwd)
test_text("sun.jdbc.odbc.JdbcOdbcDriver", 'jdbc:odbc:test_db', 'usr', 'passwd')
test_text("com.informix.jdbc.IfxDriver", 'jdbc:informix-sqli://169.0.1.225:9088/test_db:informixserver=ol_225;DB_LOCALE=pl_PL.CP1250;CLIENT_LOCALE=pl_PL.CP1250;charSet=CP1250', 'usr', 'passwd')

Is there any setting in JDBC or ODBC to have one version of code
for both drivers?

Version info:

  • Server: IBM Informix Dynamic Server Version 11.50.TC2DE
  • Client:
    • ODBC driver 3.50.TC3DE
    • IBM Informix JDBC Driver for IBM Informix Dynamic Server 3.50.JC3DE

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

墨小沫ゞ 2024-07-19 06:13:11

首先,您真的确定要使用 Informix TEXT 类型吗? 这种类型使用起来很麻烦,部分原因是您面临的问题。 它早于任何 SQL 标准中关于大对象的任何内容(TEXT 仍然不在 SQL-2003 中 - 尽管大致相同的结构,CLOB 和 BLOB)。 而且 BYTE 和 TEXT blob 的功能自 - 哦,比方说 1996 年以来就没有改变过,尽管我怀疑有选择更早日期的情况,比如 1991 年。

特别是,您计划在 TEXT 列中存储多少数据? 您的示例显示字符串“insert”; 也就是说,我认为比您实际使用的要小得多。 您应该知道,BYTE 或 TEXT 列使用表中的 56 字节描述符以及单独的页(或页集)来存储实际数据。 因此,对于这样的小字符串,这是对空间和带宽的浪费(因为 BYTE 或 TEXT 对象的数据将与行的其余部分分开在客户端和服务器之间传送)。 如果您的大小不会超过 32 KB,那么您应该考虑使用 LVARCHAR 而不是 TEXT。 如果您将使用高于此大小的数据大小,则 BYTE 或 TEXT 或 BLOB 或 CLOB 是明智的替代方案,但您应该考虑配置 blob 空间(对于 BYTE 或 TEXT)或智能 blob 空间(对于 BLOB 或 CLOB)。 您可以而且正在使用 TEXT IN TABLE,而不是在 Blob 空间中; 请注意,这样做会影响您的逻辑日志,而使用 blob 空间不会对它们产生太大影响。

大约十年来我一直在宣传的功能之一是能够将 SQL 语句中的字符串文字作为 TEXT 文字(或 BYTE 文字)传递。 这部分是因为像你这样的人的经历。 我还没有成功地将其优先于需要进行的其他更改。 当然,您需要注意,SQL 语句的最大大小为 64 KB 文本,因此如果您不小心,可能会创建太大的 SQL 语句; SQL 中的占位符(问号)通常可以防止出现问题 - 增加 SQL 语句的大小是我一直在争取的另一个功能请求,但不太热心。

好的,假设您有充分的理由使用 TEXT……接下来做什么。 我不清楚 Java(JDBC 驱动程序)在幕后做什么 - 除了太多 - 但可以肯定的是,它注意到需要 TEXT“定位器”结构并且正在以正确的方式传送参数格式。 看来 ODBC 驱动程序并没有让您沉迷于类似的恶作剧。

在我通常工作的 ESQL/C 中,代码必须以与其他所有内容不同的方式处理 BYTE 和 TEXT(并且必须再次以不同的方式处理 BLOB 和 CLOB)。 但是您可以创建并填充定位器结构(locator.h 中的 loc_t 或 ifx_loc_t - 可能不在 ODBC 目录中;默认情况下位于 $INFORMIXDIR/incl/esql 中)并将其传递给 ESQL/C 代码作为SQL 语句中相关占位符的主变量。 原则上,可能有一种可用于 ODBC 的并行方法。 不过,您可能需要查看 Informix ODBC 驱动程序手册才能找到它。

First off, are you really sure you want to use an Informix TEXT type? The type is a nuisance to use, in part because of the problems you are facing. It pre-dates anything in any SQL standard with respect to large objects (TEXT still isn't in SQL-2003 - though approximately equivalent structures, CLOB and BLOB, are). And the functionality of BYTE and TEXT blobs has not been changed since - oh, let's say 1996, though I suspect there's a case for choosing an earlier date, like 1991.

In particular, how much data are you planning to store in the TEXT columns? Your example shows the string 'insert'; that is, I presume, much much smaller than you would really use. You should be aware that a BYTE or TEXT columns uses a 56-byte descriptor in the table plus a separate page (or set of pages) to store the actual data. So, for tiny strings like that, it is a waste of space and bandwidth (because the data for the BYTE or TEXT objects will be shipped between client and server separately from the rest of the row). If your size won't get above about 32 KB, then you should look at using LVARCHAR instead of TEXT. If you will be using data sizes above that, then BYTE or TEXT or BLOB or CLOB are sensible alternatives, but you should look at configuring either blob spaces (for BYTE or TEXT) or smart blob spaces (for BLOB or CLOB). You can, and are, using TEXT IN TABLE, rather than in a blob space; be aware that doing so impacts your logical logs whereas using a blob space does not impact them anything like as much.

One of the features I've been campaigning for a decade or so is the ability to pass string literals in SQL statements as TEXT literals (or BYTE literals). That is in part because of the experience of people like you. I haven't yet been successful in getting it prioritized ahead of other changes that need to be made. Of course, you need to be aware that the maximum size of an SQL statement is 64 KB text, so you could create too big an SQL statement if you aren't careful; placeholders (question marks) in the SQL normally prevent that being a problem - and increasing the size of an SQL statement is another feature request which I've been campaigning for, but a little less ardently.

OK, assuming that you have sound reasons for using TEXT...what next. I'm not clear what Java (the JDBC driver) is doing behind the scenes - apart from too much - but it is a fair bet that it is noticing that a TEXT 'locator' structure is needed and is shipping the parameter in the correct format. It appears that the ODBC driver is not indulging you with similar shenanigans.

In ESQL/C, where I normally work, then the code has to deal with BYTE and TEXT differently from everything else (and BLOB and CLOB have to be dealt with differently again). But you can create and populate a locator structure (loc_t or ifx_loc_t from locator.h - which may not be in the ODBC directory; it is in $INFORMIXDIR/incl/esql by default) and pass that to the ESQL/C code as the host variable for the relevant placeholder in the SQL statement. In principle, there is probably a parallel method available for ODBC. You may have to look at the Informix ODBC driver manual to find it, though.

子栖 2024-07-19 06:13:11

可以通过执行以下步骤来解决此问题

  1. UNLOAD TO 'your_table.unl' SELECT * FROM your_table;

  2. 从“your_table.unl”加载插入到your_table;

根据您的要求,使用命令行中的第一个脚本以unl格式导出数据,并将其存储在用户目录中。 如果需要,将文件传输到所需的服务器,然后运行第二个脚本将数据导入到目标表中。 这样,您就不会遇到这个问题。

This can be resolved by doing following steps

  1. UNLOAD TO 'your_table.unl' SELECT * FROM your_table;

  2. LOAD from 'your_table.unl' Insert into your_table;

Based on your requirement, use the first script in command line to export the data in unl format and it will be stored in user directory. Transfer the file to required server if needed and run the second script to import the data into target table. By this, you won't face this issue.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文