Как получить доступ к скрытым столбцам из ActiveRecord (в Informix) - PullRequest
1 голос
/ 24 января 2010

Многие базы данных имеют скрытый столбец первичного ключа. MySQL реализует это как _rowid. В случае MySQL это действительно указатель на ранее определенный столбец первичного ключа. Однако в других базах данных (в моем случае, Informix) этот столбец не зависит от намеренно определенного первичного ключа. База данных, для которой я пишу код, была разработана в основном в зависимости от скрытого столбца Informix, ROWID вместо определения первичного ключа. Я подключаюсь к Informix из JRuby on Rails, используя драйвер Informix JDBC. Все хорошо, за исключением того, что я не могу найти способ сделать так, чтобы скрытый столбец rowid отображался как свойство ActiveRecord. Все остальные поля есть, только не rowid. Если я запрашиваю модель, используя Whwhat.find_by_sql («SELECT rowid, * FROM whattable»), он возвращает массив объектов «Whither», но столбец rowid отсутствует.

Я исследовал настройку драйвера JDBC, ActiveRecord или базы данных; ничто не принесло плодов.

Любое руководство будет оценено.

1 Ответ

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

Во-первых, обратите внимание, что если ваша таблица фрагментирована, у нее не будет ROWID - если вы не создали ее с помощью предложения WITH ROWIDS, и в этом случае ROWID становится индексированным физическим столбцом вместо виртуального столбца.

Во-вторых, почему бы вам просто не использовать объявленный первичный ключ для таблицы вместо того, чтобы копаться за кулисами - особенно, когда версия копания за кулисами не работает.

Мне не ясно, почему используемая вами явная запись не выполняется так, как вы запрашиваете; это может быть драйвер JDBC, который сует свой нос туда, где его нос не принадлежит. Сколько столбцов вы получите в наборе результатов? Если это не выбранное вами число (количество столбцов в таблице плюс один), значит, что-то очень подозрительно.

Если бы мне нужно было посмотреть, что драйвер JDBC отправляет на сервер, я бы включил трассировку отладки SQLI - либо на стороне клиента, либо, если клиентская сторона не взаимодействует, на стороне сервера. В обычных (на основе C) API-интерфейсах для включения отладки SQLI необходимо задать переменную среды:

SQLIDEBUG=2:sqli

Это создаст файл с именем, начинающимся с 'sqli_' в текущем каталоге процесса, выполняющего C API (ESQL / C, ODBC и т. Д.). Я предполагаю, что тот же механизм должен работать с драйвером JDBC.

Если SQLIDEBUG не работает с JDBC, то у вас гораздо более сложная работа - вам нужно включить отладку SQLI на стороне сервера.

Предполагая, что вы перехватываете выходные данные SQLI (интерфейса SQL), вы можете распечатать их, используя 'sqliprint'. Вы бы искали SQL, отправленный в IDS. Если он не содержит ROWID, вы можете быть уверены, что драйвер JDBC играет с вами в глупые игры. Однако неясно, что бы вы сделали, чтобы обойти это. Может быть, использовать псевдоним таблицы (например, 't') и:

SELECT t.ROWID, t.* FROM WhateverTable t WHERE ...

Если выяснится, что JDBC настраивает ROWID, мы могли бы также попытаться использовать псевдоним:

SELECT ROWID AS pk_column, t.* FROM WhateverTable AS t WHERE ...

(AS является необязательным после имени таблицы.)

Пожалуйста, держите нас в курсе, если вы обнаружите что-нибудь интересное или полезное.


База данных уже установлена ​​в нескольких местах и ​​содержит скомпилированные приложения (для которых источник недоступен), которые могут сломаться при изменении схемы базы данных, поэтому я не могу добавить допустимые первичные ключи. Эти приложения используют rowid в качестве первичного ключа.

OK; это проектное решение, которое должно быть рассмотрено при вашем следующем основном обновлении , если у кого-либо из ваших клиентов достаточно большие объемы данных, чтобы фрагментация могла быть полезной. Помните, что фрагментированные таблицы не имеют виртуального столбца ROWID; их можно создать с помощью физического столбца ROWID, используя предложение WITH ROWIDS в операторах CREATE TABLE или ALTER FRAGMENT.

Используя log4jdbc, я смог подтвердить, что запрос, отправляемый в Informix, включает в себя запрос на rowid. Возвращается значение, и драйвер JDBC преобразует каждый столбец в ResultSet; Я вижу, что это приведение столбца rowid (ResultSet.getLong ()). Возвращенный объект ActiveRecord, однако, не включает значение rowid. Я полагаю, что это происходит потому, что когда у драйвера JDBC запрашивается схема таблицы, которая используется для определения доступных свойств класса ActiveRecord, rowid не возвращается. Любой вклад приветствуется ...

Хорошо сделано при получении информации. Неожиданно мои знания о том, что может делать драйвер JDBC, истощаются - это может быть чем-то, что нужно обратиться в службу технической поддержки IBM / Informix. У меня возникают различные вопросы - и я даже не уверен, что проблема в драйвере JDBC, дизайне JDBC в целом или в чем-то выше JDBC; Я ни в коем случае не являюсь экспертом в этой области. (Я могу произносить Java - C; это правильно?)

Вы пытались указать ROWID в последнем столбце оператора?

SELECT *, ROWID FROM WhereEver

А как насчет этого?

SELECT *, ROWID AS T_RowID FROM WhereEver

Если драйвер JDBC видит и то, и другое, значит, он работает слишком усердно и наносит вред всем. На самом деле, я даже не уверен, что знаю, как это работает с представлениями.

У меня есть таблица элементов:

CREATE TABLE elements
(
    atomic_number   INTEGER NOT NULL UNIQUE CONSTRAINT c1_elements
                    CHECK (atomic_number > 0 AND atomic_number < 120),
    symbol          CHAR(3) NOT NULL UNIQUE CONSTRAINT c2_elements,
    name            CHAR(20) NOT NULL UNIQUE CONSTRAINT c3_elements,
    atomic_weight   DECIMAL(8,4) NOT NULL,
    stable          CHAR(1) DEFAULT 'Y' NOT NULL
                    CHECK (stable IN ('Y', 'N'))
);

INSERT INTO elements VALUES(  1, 'H',   'Hydrogen',        1.0079, 'Y');

Мне удалось создать представление для этой таблицы, включая ROWID, и затем запросить ее:

CREATE VIEW x_elements(atomic_number, symbol, name, x_rowid)
    AS SELECT atomic_number, symbol, name, ROWID AS x_rowid
         FROM elements;

SELECT * FROM x_elements WHERE x_rowid <  512;
SELECT * FROM x_elements WHERE x_rowid >= 512;

Два запроса создали несвязанные наборы данных. Вы можете найти свою систему, чтобы использовать это. При необходимости вы должны переименовать базовые таблицы (например, «WhwhatTable» становится «Base_Whwhat»), а затем создать представление «WhwhatTable», чтобы выбрать данные из Base_Wh независимо от ROWID. Я формально не пробовал это с программой JDBC, но она «должна» работать (но поскольку исходный запрос также «должен» работать, я не уверен, насколько сильно я бы полагался на утверждение «должно работать»). ).

...