Чтобы подготовиться к миграции с SQL Anywhere 16 на SQL Anywhere 17, я должен убедиться, что все функции, предоставляемые DLL, будут работать с UTF-8.
До сих пор StoredProcedures БД принимали varchar (x) в качестве параметров и передавали их в DLL, которая работала нормально.
Procedure code:
create procedure dba.stp_DLLGetData
(
in as_Input1 varchar(30),
in as_Input2 nvarchar(12)
)
external name '[email protected]'
language C_ESQL32
go
Вход 1 обрабатывается как ранее с ANSI.
Вход 2 — это та часть, которую я не могу заставить работать.
DLL code:
void GetData(an_extfn_api* extapi, void* arg_handle){
int iRc = 0;
wstring wstrInput1(L"");
wstring wstrInput2(L"");
string argTemp;
wstring wstrTemp;
LPWSTR pUnicodeString;
//get wstrInput1
if (iRc == 0){
iRc = getArgumentVarchar(extapi, arg_handle, 1, &argTemp);
if (iRc != 0){
iRc = -1;
}
else{
pUnicodeString = ConvertToUNICODE(argTemp.c_str());
wstrInput1 = wstring(pUnicodeString);
free(pUnicodeString);
argTemp.clear();
}
}
//get wstrInput2
if (iRc == 0){
iRc = getArgumentNvarchar(extapi, arg_handle, 2, &wstrInput2);
if (iRc != 0){
iRc = -1;
}
}
}
int getArgumentVarchar(an_extfn_api* extapi, void* arg_handle, int iArgNum, string* argString){
short params;
unsigned offset;
an_extfn_value argument;
params = extapi->get_value(arg_handle, iArgNum, &argument);
if (params == 0 || argument.data == NULL){
return 1;
}
if (argument.type != DT_VARCHAR){
return -1;
}
argString->clear();
offset = 0;
for( ; params != 0; ){
if (argument.data == NULL) break;
argString->append((char *) argument.data, argument.piece_len);
offset += argument.piece_len;
if (argument.piece_len == 0) break;
params = extapi->get_piece(arg_handle, iArgNum, &argument, offset);
}
return 0;
}
int getArgumentNvarchar(an_extfn_api* extapi, void* arg_handle, int iArgNum, wstring* argString){
short params;
unsigned offset;
an_extfn_value argument;
wchar_t* bla;
params = extapi->get_value(arg_handle, iArgNum, &argument);
if (params == 0 || argument.data == NULL){
return 1;
}
if (argument.type != DT_NVARCHAR){ //error 1
return -1;
}
argString->clear();
offset = 0;
for( ; params != 0; ){
if (argument.data == NULL) break;
argString->append((wchar_t*) argument.data, argument.piece_len); //error2
offset += argument.piece_len;
if (argument.piece_len == 0) break;
params = extapi->get_piece(arg_handle, iArgNum, &argument, offset);
}
return 0;
}
Сначала я подумал: «Эй, легко, поменяйте местами типы данных и все», но оказалось, что все сложнее.
Согласно документации БД, nvarchar в SQL должен ссылаться на DT_NVARCHAR в C.
-SQL- | -data type- | -sqldef.h C type-
VARCHAR | DT_VARCHAR | Character data, with specified length
LONG VARCHAR | DT_LONGVARCHAR | Character data, with specified length
NVARCHAR | DT_NVARCHAR | UTF-8 character data, with specified length
LONG NVARCHAR | DT_LONGNVARCHAR | UTF-8 character data, with specified length
Во время отладки (входные параметры бота содержат строку ‘evo01’), когда я проверяю тип данных аргумента (error1), типом аргумента аргумента тип-аргумента является DT_LONGVARCHAR вместо DT_NVARCHAR.
«Нет проблем», — подумал я, возможно, оценка как-то не так.
Если я пропущу проверку типа данных и продолжу, я получаю тарабарщину только после применения wchar_t * к аргументу.
Если я применяю char * к тому же nvarchar arguments.data, то получаю вместо ‘evo01’.
Может кто-то указать, что я делаю не так?
РЕДАКТИРОВАТЬ: обновить
Поскольку БД продолжает передавать недопустимый контент, и у меня заканчиваются идеи, я решил использовать обходной путь и передать аргументы через длинный двоичный файл.
Не самое выгодное решение, но работающее без нареканий.
Задача ещё не решена.
Других решений пока нет …