This is an extension of a question I asked before: C#: How do I get the ID number of the last row inserted using Informix
I am writing some code in C# to insert records into the informix db using the .NET Informix driver. I was able to get the id of the last insert, but in some of my tables the 'serial' attribute is not used. I was looking for a command similar to the following, but to get rowid instead of id.
SELECT DBINFO ('sqlca.sqlerrd1') FROM systables WHERE tabid = 1;
And yes, I do realize working with the rowid is dangerous because it is not constant. However, I plan to make my application force the client apps to reset the da开发者_JAVA百科ta if the table is altered in a way that the rowids got rearranged or the such.
One problem with ROWID is that it is a 4-byte quantity but the value used on a fragmented table is an 8-byte quantity (nominally FRAGID and ROWID), but Informix has never exposed the FRAGID.
In theory, the SQLCA data structure reports the ROWID in the sqlca.sqlerrd[5]
element (assuming C-style indexing from 0; it is sqlca.sqlerrd[6]
in Informix 4GL which indexes from 1). If anything was going to work with DBINFO, it would be DBINFO('sqlca.sqlerrd5')
, but I get:
SQL -728: Unknown first argument of dbinfo(sqlca.sqlerrd5).
So, the indirect approach using DBINFO is not on. In ESQL/C, where sqlca
is readily available, the information is available too:
SQL[739]: begin;
BEGIN WORK: Rows processed = 0
SQL[740]: create table p(q integer);
CREATE TABLE: Rows processed = 0
SQL[741]: insert into p values(1);
INSERT: Rows processed = 1, Last ROWID = 257
SQL[742]: select dbinfo('sqlca.sqlerrd5') from dual;
SQL -728: Unknown first argument of dbinfo(sqlca.sqlerrd5).
SQLSTATE: IX000 at /dev/stdin:4
SQL[743]:
I am not a user of C# or the .NET driver, so I have no knowledge of whether there is a back-door mechanism to get at the information. Even in ODBC, there might not be a front-door mechanism to get at it, but you could drop into C code to read the global data structure easily enough:
#include <sqlca.h>
#include <ifxtypes.h>
int4 get_sqlca_sqlerrd5(void)
{
return sqlca.sqlerrd[5];
}
Or, even:
int4 get_sqlca_sqlerrdN(int N)
{
if (N >= 0 && N <= 5)
return sqlca.sqlerrd[N];
else
return -22; /* errno 22 (EINVAL): Invalid argument */
}
If C# can access DLL's written in C, you could package that up.
Otherwise, the approved way of identifying rows of data is via the primary key (or any other unique identifier, sometimes known as an alternative key or candidate key) for the row. If you don't have a primary key or other unique identifier for the row, you are making life difficult for yourself. If it is a compound key, that 'works' but could be inconvenient. Maybe you need to consider adding a SERIAL column (or BIGSERIAL column) to the table.
You can use:
SELECT ROWID
FROM TargetTable
WHERE PK_Column1 = <value1> AND PK_Column2 = <value2>
or something similar to obtain the ROWID, assuming you can identify the row accurately.
In dire straights, there is a mechanism to add a physical ROWID column to a fragmented table (normally, it is a virtual column). You'd then use the query above. This is not recommended, but the option is there.
精彩评论