Firebird/IBPP вставляют молча

У меня есть приложение C++, которое использует встроенную базу данных Firebird (например, используя fbembed.dll в Windows для встроенного использования) через библиотеку IBPP. В настоящее время я использую версию 2.5.3 Firebird и 2.5.3.1 IBPP. Проблема, с которой я сталкиваюсь, заключается в том, что, когда я пытаюсь вставить данные, которые не могут быть вставлены из-за проблем с размером столбца или нарушения ограничений (например, сбой вставки), я не получаю ошибок или указаний на то, что вставка не удалась.

В качестве (упрощенного, но представительного) примера, у меня есть таблица типа:

create table USER_TABLE (
    ID BIGINT not null,
    USER_ID VARCHAR(10) not null,
    DISPLAY_NAME VARCHAR(50) not null,
-- etc...
    primary key (ID),
    unique (USER_ID)
);

Столбец ID заполняется генератором в триггере перед вставкой. Теперь я пытаюсь вставить из моего приложения следующий код:

const string SQL_STMT = "insert into USER_TABLE "
        "(USER_ID, DISPLAY_NAME, etc) "
        "values (?, ?, ?);";
IBPP::Statement stmt = IBPP::StatementFactory(m_db, m_tr, SQL_STMT);
stmt->Set(1, userDataObject.getUserId());//returns const string&,
stmt->Set(2, userDataObject.getDisplayName());//returns const string&
//etc, etc...
stmt->Execute();

Если мой userDataObject.getUserId() значение слишком длинное для столбца 1234567890xxx Я не получу исключения, как я ожидал. Я могу (очевидно, успешно) получить идентификатор внутри той же транзакции с select ID from user_table where ... после выполнения вставки или через ... returning ID в конце SQL_STMT переменная выше. Но как только транзакция зафиксирована и другие части кода пытаются получить значения в таблице, ее там нет. Ни в коем случае я не получаю ошибку / исключение.

Есть идеи, почему я не получаю ошибку в этих обстоятельствах?

1 ответ

Решение

Итак, несколько недель спустя мы с коллегой наткнулись на причину этой проблемы, глядя на немного другую проблему. Мы выполняли нашу работу / тестирование с использованием 64-битной цепочки инструментов Microsoft Visual Studio C++. Библиотеки Firebird возвращают информацию о состоянии и ошибках через массив типа ISC_STATUS, Библиотеки определяют это как typedef intptr_t размер указателя и, следовательно, в 64-битной системе равен 64 битам.

Библиотека IBPP динамически загружает клиентские библиотеки Firebird. Когда он определяет свою версию ISC_STATUS, он определяет это как long, В Linux/GCC я думаю, что это работает (например, будет 32 бита в 32-битной архитектуре и 64-битной в 64-битной архитектуре), но в Microsoft Visual C++ long всегда 32 бита. В результате, когда мы скомпилировали и запустили 64-битную конфигурацию, она интерпретировала массив 64-битных целых как массив 32-битных целых. Результатом было то, что, поскольку все значения, которые были помещены в массив, были положительными целыми числами, которые помещаются в 32 бита, оказалось, что каждое другое значение в массиве состояния было 0. IBPP обнаруживает ошибки, проверяя ненулевое значение в из-за этого второе место в массиве, которое при 64-битной обработке всегда будет равно нулю.

Решением было обновить определение IBPP ISC_STATUS чтобы правильно соответствовать используемой клиентской библиотеке Firebird (это находится в заголовочном файле 'ibase.h').

Другие вопросы по тегам