Я работаю с IBPP на Visual Studio 2015 / VC ++. IBPP — это оболочка c ++ для API Firebird / Interbase.
IBPP, клиентский интерфейс C ++ к серверу Firebird
Часть этого пакета — небольшой набор тестов, вы можете скачать его здесь:
ibpp-2-5-3-1-src.zip
Для начала с набором тестов вы найдете простой пакетный файл для его компиляции в
х: … \ ППИР-2-5-3-1-Src \ Тесты \ VS2005 \ Простейшие-build.bat
Он прекрасно компилируется с нативными наборами инструментов x86 и x64 vc ++ 2015.
Перед компиляцией необходимо отредактировать строки с 84 по 86
х: … \ ППИР-2-5-3-1-Src \ Тесты \ tests.cpp
const char* DbName = "x:/ibpptest/test.fdb"; // FDB extension (GDB is hacked by Windows Me/XP "System Restore")
const char* BkName = "x:/ibpptest/test.fbk";
const std::string ServerName = ""; //"localhost"; // Change to "" for local protocol / embedded
Пожалуйста, имейте в виду, чтобы создать каталог x:\ibpptest\
,
Кроме того, вам необходимо скачать файлы fblient, которые не доступны сами по себе, но являются частью всего архива сервера. Получите эти оба файла:
32-битный встроенный
а также
64-битный встраиваемый
.
Для упрощения создайте две директории помимо x:\...\ibpp-2-5-3-1-src\tests\vs2005\
:
x:\...\ibpp-2-5-3-1-src\tests\vs2015x86\
x:\...\ibpp-2-5-3-1-src\tests\vs2015x84\
и скопировать x:\...\ibpp-2-5-3-1-src\tests\vs2005\simplest-build.bat
в них. Теперь скопируйте файлы fbclient (32-разрядные в x86, 64-разрядные в x64) в следующие каталоги:
intl/*
udf/*
fbembed.dll
firebird.msg
ib_util.dll
icudt30.dll
icuin30.dll
icuuc30.dll
msvcp80.dll
msvcr80.dll
Теперь вы можете скомпилировать и запустить tests.exe. Двоичный файл x86 генерирует некоторые ошибки в тесте 6, и это нормально, потому что вы используете встроенную версию файлов fblient. Двоичный файл x64 будет отображаться в окне сбоя программы Windows. Это происходит в Test3, когда набор тестов активирует исключение:
try
{
#if defined(IBPP_WINDOWS) && defined(_DEBUG)
OutputDebugString(_("An exception will now get logged in the debugger: this is expected.\n"));
#endif
st1->ExecuteImmediate( "CREATE SYNTAX ERROR(X, Y) AS ""SELECT ERRONEOUS FROM MUSTFAIL M" );
}
catch(IBPP::SQLException& e)
{
//~ std::cout<< e.what();
if (e.EngineCode() != 335544569)
{
_Success = false;
printf(_("The error code returned by the engine during a\n""voluntary statement syntax error is unexpected.\n"));
}
}
В двоичном файле x86 это исключение было получено, как и ожидалось, но в двоичном файле x64 это не так. Кто-нибудь знает, как добиться аналогичного исключения исключений в бинарном x64?
Заранее благодарю за любую помощь!
Предупреждение: я использовал среду Visual Studio 2017 для запуска файла simplest-build.bat.
Из приведенных ниже доказательств видно, что существует проблема с разветвлением или другим различием компиляции между 32-битной и 64-битной версиями службы Firebird, которая вызывает эту проблему.
Решение: функция-член EngineCode () не существует в 64-битной версии. Вы должны использовать функцию-член what () исключения, как показано в закомментированной строке внутри блока catch Test3 (). Если вы хотите использовать информацию EngineCode, вам придется проанализировать ее из строки what (), поскольку она содержит всю информацию, которая изначально была предоставлена как отдельные элементы данных в классе IBPP :: SQLExceptionImpl для 32-разрядных систем.
try
{
#if defined(IBPP_WINDOWS) && defined(_DEBUG)
OutputDebugString(_("An exception will now get logged in the debugger: this is expected.\n"));
#endif
st1->ExecuteImmediate( "CREATE SYNTAX ERROR(X, Y) AS ""SELECT ERRONEOUS FROM MUSTFAIL M" );
}
catch(IBPP::SQLException& e)
{
//~ std::cout<< e.what();
printf(e.what());
//if (e.EngineCode() != 335544569)
//{
// _Success = false;
// printf(_("The error code returned by the engine during a\n"// "voluntary statement syntax error is unexpected.\n"));
//}
}
Результат вызова ().
*** IBPP::SQLException ***
Context: Statement::ExecuteImmediate( CREATE SYNTAX ERROR(X, Y) AS SELECT ERRONEOUS FROM MUSTFAIL M )
Message: isc_dsql_execute_immediate failed
SQL Message : -104
can't format message 13:896 -- message file C:\WINDOWS\SYSTEM32\firebird.msg not found
Engine Code : 335544569
Engine Message :
Dynamic SQL Error
SQL error code = -104
Token unknown - line 1, column 8
SYNTAX
Головоломка: Statement.cpp показывает использование IBPP :: SQLExceptionImpl и других … ExceptionImpl, поэтому я должен верить, что этот исходный код является 32-битной ветвью. Если предполагается, что это общая ветка как для 32, так и для 64 бит, то я не вижу, как это может работать.
Есть два заголовочных файла, которые определяют классы исключений. Я считаю, что _ibbp.h использовался для компиляции 32-битного клиента, а ibbp.h использовался для 64-битного клиента. Я пришел к этим выводам, изменив предложение catch в Test3 (), чтобы увидеть возможные исключения. Классы … ExceptionImpl будут компилироваться только с 32-битными клиентскими библиотеками и не будут компилироваться с 64-битными библиотеками.
Из _ibpp.h (32-битные библиотеки fbclient распознают эти классы. 64-битные библиотеки fbclient не распознают.)
///////////////////////////////////////////////////////////////////////////////
//
// Implementation of the "hidden" classes associated with their public
// counterparts. Their private data and methods can freely change without
// breaking the compatibility of the DLL. If they receive new public methods,
// and those methods are reflected in the public class, then the compatibility
// is broken.
//
///////////////////////////////////////////////////////////////////////////////
//
// Hidden implementation of Exception classes.
//
/*
std::exception
|
IBPP::Exception
/ \
/ \
IBPP::LogicException ExceptionBase IBPP::SQLException
| \ / | \ /
| LogicExceptionImpl | SQLExceptionImpl
| |
IBPP::WrongType |
\ |
IBPP::WrongTypeImpl
*/
Из ibpp.h (оба набора fbclient dll распознают эти классы)
/* IBPP never return any error codes. It throws exceptions.
* On database engine reported errors, an IBPP::SQLException is thrown.
* In all other cases, IBPP throws IBPP::LogicException.
* Also note that the runtime and the language might also throw exceptions
* while executing some IBPP methods. A failing new operator will throw
* std::bad_alloc, IBPP does nothing to alter the standard behaviour.
*
* std::exception
* |
* IBPP::Exception
* / \
* IBPP::LogicException IBPP::SQLException
* |
* IBPP::WrongType
*/
Во всех файлах tests.cpp единственный улов для IBPP :: SQLException находится в Test3 (). Любой другой улов использует IBPP :: Exception.
Так что эта проблема будет проявляться только в Test3 () при компиляции для 64-битной системы, но я думаю, что она будет проявляться всякий раз, когда IBPP :: SQLException используется в 64-битной реализации.
После долгих исследований я нашел причину. Я был неправ, полагая, что обработка исключений в x86 и x64 отличается. Библиотека IBPP содержит ошибку (с 10 лет!), Которая возникает в сценарии x64 / windows только тогда, когда библиотека firebird сообщает вызывающему (сложное) состояние ошибки.
Итак, что происходит:
Тестовая программа вызывает библиотеку IBPP. Библиотека IBPP вызывает API / библиотеку Firebird. Библиотека Firebird сообщает о своих результатах вызовов в массиве long [20], они называют его «ISC_STATUS vector». Библиотека IBPP проверяет эти результаты и в случае ошибки выдает исключение. Тестовая программа перехватывает такие исключения и сообщает о них для использования.
Все идет нормально. Но ошибка в том, что IBPP определяет ISC_STATUS как массив [20] longs как firebird, который он также делал до v2.0 — который поддерживает только окна x86. Начиная с v2.1, Firebird поддерживает 64-разрядные Windows и определяет ISC_STATUS как массив intptr_t, что приводит к «long long» в компиляторах LLP64 для Windows x64 и к длинным в компиляторах Linux LP64 — оба имеют ширину 64 бита. На компиляторах ILP32 для windows и linux x86 intptr_t имеет ширину 32 бита.
IBPP не закрывает пробел для firebird и остается в своем определении ISC_STATUS так долго, что приводит к 32-битному типу данных в системах LLP64 windows x64 (но к 64-битным в linux, так как gcc в linux использует систему LP64, так что ошибка происходит только на окнах).
Таким образом, API Firebird x64 сообщает о 20 целых числах состояния массиву «по ссылочному параметру» [20] из 64-битных целых чисел. Библиотека FBPP передает массив [20] из 32-битных целых чисел. Когда API Firebird сохраняет значения во второй половине массива, он перезаписывает память вызывающей стороны. В этом случае следующие байты после вектора ISC_STATUS заняты строковым объектом c ++. И массив состояний, и строка являются частью класса IBS (interbase status). Многие из функций IBPP часто создают экземпляр локального объекта этого класса для управления результатами API firebird и строкой описания ошибки. Когда функции выходят, среда очищает такие локальные объекты и пытается освободить строку, но ее метаданные в памяти были перезаписаны API Firebird.
Таким образом, очистка локального объекта IBS приводит к неизвестным программным исключениям, которые переопределяют исключения, создаваемые платформой IBPP. И это исключение отлавливается не тестовой программой, а windows / dr. уотсон.
Я исправил определение ISC_STATUS от «long» до «intptr_t», и все работает как положено.
Спасибо всем за ваши советы.