Informix: как получить rowid последнего оператора вставки

Это расширение вопроса, который я задавал ранее: C#: как получить идентификационный номер последней строки, вставленной с помощью Informix

Я пишу код на С# для вставки записей в базу данных informix с помощью драйвера .NET Informix. Мне удалось получить идентификатор последней вставки, но в некоторых моих таблицах атрибут "serial" не используется. Я искал команду, похожую на следующую, но для получения rowid вместо id.

SELECT DBINFO ('sqlca.sqlerrd1') FROM systables WHERE tabid = 1;

И да, я понимаю, что работать с rowid опасно, потому что он непостоянен. Тем не менее, я планирую заставить свое приложение заставить клиентские приложения сбрасывать данные, если таблица изменена таким образом, что идентификаторы строк были переставлены или что-то в этом роде.


person myermian    schedule 24.11.2010    source источник
comment
Можете ли вы выбрать идентификатор строки, используя последний идентификатор вставки в вашем предложении where?   -  person johnny    schedule 24.11.2010
comment
Ну, нет... потому что некоторые таблицы не используют тип 'serial'. Таким образом, во всех этих случаях он вернет «0».   -  person myermian    schedule 24.11.2010


Ответы (1)


Одна проблема с ROWID заключается в том, что это 4-байтовая величина, но значение, используемое в фрагментированной таблице, представляет собой 8-байтовую величину (номинально FRAGID и ROWID), но Informix никогда не раскрывала FRAGID.

Теоретически структура данных SQLCA сообщает ROWID в элементе sqlca.sqlerrd[5] (предполагается, что индексация в стиле C начинается с 0; это sqlca.sqlerrd[6] в Informix 4GL, который индексирует с 1). Если бы что-то работало с DBINFO, это было бы DBINFO('sqlca.sqlerrd5'), но я получаю:

SQL -728: Unknown first argument of dbinfo(sqlca.sqlerrd5).

Итак, косвенный подход с использованием DBINFO не работает. В ESQL/C, где sqlca легкодоступна, информация также доступна:

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]: 

Я не являюсь пользователем C# или драйвера .NET, поэтому я не знаю, существует ли какой-нибудь черный ход для получения информации. Даже в ODBC может не быть внешнего механизма для доступа к нему, но вы можете заглянуть в код C, чтобы достаточно легко прочитать глобальную структуру данных:

#include <sqlca.h>
#include <ifxtypes.h>
int4 get_sqlca_sqlerrd5(void)
{
    return sqlca.sqlerrd[5];
}

Или даже:

int4 get_sqlca_sqlerrdN(int N)
{
    if (N >= 0 && N <= 5)
        return sqlca.sqlerrd[N];
    else
        return -22;  /* errno 22 (EINVAL): Invalid argument */
}

Если C# может получить доступ к DLL, написанным на C, вы можете упаковать это.

В противном случае утвержденным способом идентификации строк данных является использование первичного ключа (или любого другого уникального идентификатора, иногда называемого альтернативным ключом или ключом-кандидатом) для строки. Если у вас нет первичного ключа или другого уникального идентификатора строки, вы усложняете себе жизнь. Если это составной ключ, это «работает», но может быть неудобно. Возможно, вам нужно добавить в таблицу столбец SERIAL (или столбец BIGSERIAL).

Вы можете использовать:

SELECT ROWID
  FROM TargetTable
 WHERE PK_Column1 = <value1> AND PK_Column2 = <value2>

или что-то подобное для получения ROWID, если вы можете точно идентифицировать строку.

В крайнем случае существует механизм добавления физического столбца ROWID к фрагментированной таблице (обычно это виртуальный столбец). Затем вы должны использовать запрос выше. Это не рекомендуется, но вариант есть.

person Jonathan Leffler    schedule 27.11.2010
comment
Если я пойду по пути использования кода C, есть ли что-нибудь помимо этого кода, что мне понадобится? Я знаю, что C# может использовать DllImport(...) для вызова неуправляемого кода, но мне интересно, не нужно ли коду C иметь ссылку на соединение Informix или команду Informix, которую он выполняет? - person myermian; 29.11.2010
comment
@myermian: я не знаю, это короткий ответ ... вам, вероятно, потребуется скомпилировать с флагами потоковой передачи (esql -thread ... в Unix; вероятно, то же самое в Windows), чтобы sqlca сопоставлялась с функцией который возвращает (зависящий от потока) указатель на структуру sqlca. Однако вам, вероятно, больше ничего не понадобится; он будет вызываться в контексте потока и будет (должен) давать вам значение, связанное с вашим потоком. - person Jonathan Leffler; 30.11.2010