如何从 ActiveRecord 访问隐藏列(在 Informix 中)
许多数据库都有隐藏的主键列。 MySQL 将其实现为 _rowid。在 MySQL 的例子中,它实际上是一个指向先前定义的主键列的指针。然而,在其他数据库(在我的例子中,Informix)中,该列独立于故意定义的主键。我正在编码的数据库主要是根据 Informix 隐藏列 ROWID 而不是定义主键的实践来设计的。我正在使用 Informix JDBC 驱动程序从 JRuby on Rails 连接到 Informix。一切都很好,只是我无法找出使隐藏的 rowid 列显示为 ActiveRecord 属性的方法。所有其他字段都在那里,只是没有 rowid。如果我使用 Whatever.find_by_sql("SELECT rowid,* FROMwhatevertable") 查询模型,它会返回一个“Whatever”对象数组,但 rowid 列不存在。
我研究了调整 JDBC 驱动程序、ActiveRecord 或数据库;一切都没有取得成果。
任何指导将不胜感激。
Many databases have a hidden primary key column. MySQL implements this as _rowid. In MySQL's case it is really a pointer to a previously defined primary key column. However in other databases (in my case, Informix), this column is independent of a deliberately defined primary key. The database which I'm coding for was designed mostly under the practice of depending on the Informix hidden column, ROWID instead of defining a primary key. I'm connecting to Informix from JRuby on Rails using the Informix JDBC driver. All is good except that I cannot figure out a way to make the hidden rowid column show up as an ActiveRecord property. All of the other fields are there, just not rowid. If I query a model using Whatever.find_by_sql("SELECT rowid,* FROM whatevertable") it returns an array of "Whatever" objects but the rowid column is not there.
I've investigated tweaking the JDBC driver, ActiveRecord or the database; nothing has borne fruit.
Any guidance would be appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先,请注意,如果您的表是碎片化的,则它将不会有 ROWID - 除非您使用WITH ROWIDS 子句创建它,在这种情况下,ROWID 将成为索引物理列而不是虚拟列。
其次,为什么不直接使用表的声明主键,而不是在幕后进行深入研究 - 特别是当幕后深入研究版本不起作用时。
我不清楚为什么您使用的显式符号没有按照您的要求进行;这可能是 JDBC 驱动程序把它的鼻子伸到了它不该伸手的地方。您在结果集中返回了多少列?如果它不是您选择的数字(表中的列数加一),那么有些事情就很可疑。
如果我需要查看 JDBC 驱动程序发送到服务器的内容,我将启用 SQLI 调试跟踪 - 无论是在客户端,还是在服务器端(如果客户端不配合)。在普通(基于 C 的)API 中,启用 SQLI 调试只需设置一个环境变量:
这将在运行 C 的进程的当前目录中创建一个名称以“
sqli_
”开头的文件。 API(ESQL/C、ODBC 等)。我认为 JDBC 驱动程序应该使用相同的机制。如果 SQLIDEBUG 不能与 JDBC 一起使用,那么您的工作就会困难得多 - 您需要在服务器端启用 SQLI 调试。
假设您捕获了 SQLI(SQL 接口)输出,则可以使用“
sqliprint
”打印它。您将查找发送到 IDS 的 SQL。如果它不包含 ROWID,那么您可以相当确定 JDBC 驱动程序正在与您玩愚蠢的游戏。但是,尚不清楚您将采取什么措施来解决这个问题。也许可以尝试使用表别名(例如“t”)并且:如果事实证明 JDBC 正在调整 ROWID,我们也可以尝试使用别名:(
表名称后面的 AS 是可选的。)
如果您发现任何问题,请随时通知我们有趣或有用。
好的;如果您的任何客户拥有足够大的数据量,碎片化可能是有益的,那么您应该在下一次主要升级时审查这一设计决策。请记住,碎片表没有虚拟 ROWID 列;您可以通过在 CREATE TABLE 或 ALTER FRAGMENT 语句中使用WITH ROWIDS 子句来使用物理 ROWID 列创建它们。
在获取信息方面做得很好。顺便说一句,我对 JDBC 驱动程序可能执行的操作的了解开始耗尽 - 这可能需要向 IBM/Informix 技术支持寻求帮助。我的脑海中浮现出各种问题 - 我什至不确定问题是否出在 JDBC 驱动程序、整体 JDBC 设计中,或者是位于 JDBC 之上的某些东西;我无论如何都不是这个领域的专家。 (我可以拼写 Java - C;对吗?)
您是否尝试过将 ROWID 放入语句的最后一列中?
那么别名呢?
如果 JDBC 驱动程序看穿了这两点,那么它就工作得太辛苦了,给每个人带来了伤害。事实上,我什至不确定我是否知道它如何与视图一起使用。
我有一个元素表:
我能够在该表上创建一个视图(包括 ROWID),然后对其进行查询:
这两个查询生成了不相交的数据集。您也许可以欺骗您的系统来利用此漏洞。如有必要,您可以重命名基表(例如,“WhateverTable”变为“Base_Whatever”),然后创建视图“WhateverTable”以从 Base_Whatever 中选择数据以及 ROWID。我还没有用 JDBC 程序正式尝试过这一点,但它“应该”工作(但由于原始查询也“应该”工作,我不确定我会在多大程度上依赖“应该工作”断言)。
First, note that if your table is fragmented, it won't have a ROWID - unless you created it using the WITH ROWIDS clause, in which case the ROWID becomes an indexed physical column instead of a virtual column.
Second, why don't you just use the declared primary key for the table instead of delving behind the scenes - especially when the delving behind the scenes version is not working.
I'm not clear why the explicit notation you are using is not doing as you request; that could be the JDBC driver poking its nose in where its nose does not belong. How many columns do you get back in the result set? If it isn't the number you select (the number of columns in the table plus one), then something is very fishy.
If I needed to see what the JDBC driver is sending to the server, I would enable SQLI debug tracing - either at the client side or, if the client side does not cooperate, on the server side. In normal (C-based) APIs, enabling SQLI debug is a matter of setting an environment variable:
This will create a file with a name starting '
sqli_
' in the current directory of the process running the C API (ESQL/C, ODBC, etc). I assume that the same mechanism should work with the JDBC driver.If SQLIDEBUG does not work with JDBC, then you have a much harder job - you need to enable SQLI debug on the server side.
Assuming you trap the SQLI (SQL Interface) output, you can then print it using '
sqliprint
'. You'd look for the SQL sent to IDS. If it does not contain the ROWID, then you can be fairly sure the JDBC driver is playing silly games with you. However, it is not clear what you'd do to work around that. Maybe try a table alias (such as 't') and:If it turns out that JDBC is tweaking ROWID, we could try aliassing that too:
(The AS is optional after the table name.)
Please keep us posted if you discover anything interesting or useful.
OK; that is a design decision that should be reviewed at your next main upgrade if any of your customers have large enough volumes of data that fragmentation might be beneficial. Remember, fragmented tables do not have a virtual ROWID column; you can create them with a physical ROWID column by using the WITH ROWIDS clause in the CREATE TABLE or ALTER FRAGMENT statements.
Well done on getting the information. Offhand, my knowledge of what the JDBC driver might be doing starts to run out - this might be something to take to IBM/Informix Technical Support. Various questions arise in my mind - and I'm not even sure whether the problem is in the JDBC driver, the JDBC design overall, or something sitting above JDBC; I am not by any stretch of my imagination an expert in the area. (I can spell Java - C; is that right?)
Have you tried fiddling the ROWID into the last column in the statement?
What about aliassing that?
If the JDBC driver sees through both those, then it is working far too hard and doing everyone a disservice. Indeed, I'm not even sure I know how it works with views.
I have a table of elements:
I was able to create a view on that table including the ROWID and then query it:
The two queries produced disjoint sets of data. You may be able to finagle your system to exploit this. If necessary, you'd rename the base tables (e.g. 'WhateverTable' becomes 'Base_Whatever') and then create the view 'WhateverTable' to select the data from Base_Whatever, along with the ROWID. I haven't formally tried this with a JDBC program, but it 'ought' to work (but since the original query also 'ought' to work, I am not sure how much reliance I would place on the 'ought to work' assertion).