Есть тарблема с SQL_TEXT & SQL_VARYING парамтрами XSQLVAR.
Есть процедура:
procedure TZIbSql.SetParameter(SqlVar: PXSQLVAR; Value: variant);
....
case SqlVar.sqltype and (not 1) of
SQL_TEXT, SQL_VARYING:
begin
TempStr := VarToStr(Value);
SqlVar^.sqllen := Length(TempStr);
ReallocMem(SqlVar^.sqldata, SqlVar^.sqllen + 1);
if Length(TempStr) > 0 then
Move(TempStr[1], SqlVar^.sqldata^, SqlVar^.sqllen);
Запрос след. рода: 'INSERT INTO test (id, name) VALUES(?,?)'
Я делаю подготовку запроса создаю StatementHandle и распределяю XSQLDA.
Потом делаю подготовку параметров для запроса распределяю для этого XSQLDA и заполняю параметры в SetParameter
Далее выполняю
"Sql error: Dynamic SQL error. Error: -804. An error found in the application input parameter for the SQL statement.
Если убрать текстовый параметр/поле — "name" все работает отлично. я думаю что проблема с заполнением SqlVar^.sqldata для текстовых полей.
Примечание: Мои компоненты работают нормально с простымим запросами (без параметров) возвращают все данные корректно. Проблема заключается в запросах с параметрами.
--
То, что вы уникальны еще не значит, что от вас есть толк
Здравствуйте, Sergey Merkuriev, Вы писали:
SM>Есть процедура: SM>
procedure TZIbSql.SetParameter(SqlVar: PXSQLVAR; Value: variant);
SM>....
SM>case SqlVar.sqltype and (not 1) of
SM> SQL_TEXT, SQL_VARYING:
SM> begin
SM> TempStr := VarToStr(Value);
SM> SqlVar^.sqllen := Length(TempStr);
SM> ReallocMem(SqlVar^.sqldata, SqlVar^.sqllen + 1);
SM> if Length(TempStr) > 0 then
SM> Move(TempStr[1], SqlVar^.sqldata^, SqlVar^.sqllen);
Для начала, что касается SQL_VARYING
Нужно выделять память sqlvar.sqllen+sizeof(short)
В первых двух байтах (short) указывается длина строки.
Сама строка идет после этих двух байт.
Нулевой символ не обязателен.
В sqlvar.sqllen указывается длина буфера
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Sergey Merkuriev, Вы писали:
SM>Есть тарблема с SQL_TEXT & SQL_VARYING парамтрами XSQLVAR.
[skip]
Я думаю, надо различать случаи SQL_TEXT и SQL_VARYING
Когда тип SQL_TEXT, то строка задаётся нулём в конце, когда SQL_VARYING — то первые два байта
это длина строки.
Поэтому, либо надо анализировать SqlVar.sqltype, или
явно указывать
SqlVar.sqltype := SQL_TEXT or (SqlVar.sqltype and 1);
Здравствуйте, mrhru, Вы писали:
M>Я думаю, надо различать случаи SQL_TEXT и SQL_VARYING M>Когда тип SQL_TEXT, то строка задаётся нулём в конце, когда SQL_VARYING — то первые два байта M>это длина строки.
В обоих случаях терминальный нулевой символ не используется.
Для SQL_TEXT длина строки определяется из XSQLVAR::sqllen
Плавали — знаем. Очень удивлюсь если это не так
Терминальные нули используются в массивах IB.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Здравствуйте, Коваленко Дмитрий, Вы писали:
M>>Я думаю, надо различать случаи SQL_TEXT и SQL_VARYING M>>Когда тип SQL_TEXT, то строка задаётся нулём в конце, когда SQL_VARYING — то первые два байта M>>это длина строки.
КД>В обоих случаях терминальный нулевой символ не используется. КД>Для SQL_TEXT длина строки определяется из XSQLVAR::sqllen
КД>Плавали — знаем. Очень удивлюсь если это не так
Да, совершенно верно, не используются!
КД>Терминальные нули используются в массивах IB.
Нужно выделять память sqlvar.sqllen+sizeof(short)
В первых двух байтах (short) указывается длина строки.
Сама строка идет после этих двух байт.
Нулевой символ не обязателен.
В sqlvar.sqllen указывается длина буфера
Сделал так как ты говоришь:
SQL_VARYING:
begin
TempStr := VarToStr(Value);
if SqlVar^.sqllen > length(TempStr) then
Len := length(TempStr)
else Len := SqlVar^.sqllen;
ReallocMem(SqlVar.sqldata, SqlVar^.sqllen + 2);
PShort(SqlVar^.sqldata)^ := SqlVar^.sqllen;
StrLCopy(SqlVar^.sqldata + 2, PChar(TempStr), Len);
end;
SQL_TEXT:
begin
TempStr := VarToStr(Value);
if SqlVar^.sqllen > length(TempStr) then
Len := Length(TempStr)
else Len := SqlVar^.sqllen;
ReallocMem(SqlVar^.sqldata, SqlVar^.sqllen + 1);
StrLCopy(SqlVar^.sqldata, Pchar(TempStr), Len);
end;
не работатет
--
То, что вы уникальны еще не значит, что от вас есть толк
Здравствуйте, Sergey Merkuriev, Вы писали:
SM>Этот пример приводился в ApiGuide. Теперь все работает ().
SM>Вариант же который ты советуешь ниже упорно не хочет работать. Можеть написать правильный код?
Гм, извиняюсь. Я, собственно приведенный вариант (из API) и использую.
Т.е. присвоение через SQL_TEXT.
Спасибо той доброй душе, которая отформатировала текст
SQL_VARYING:
begin
TempStr := VarToStr(Value);
if SqlVar^.sqllen > length(TempStr) then
Len := length(TempStr)
else
Len := SqlVar^.sqllen;
ReallocMem(SqlVar.sqldata, SqlVar^.sqllen + 2);
PShort(SqlVar^.sqldata)^ := SqlVar^.sqllen;
StrLCopy(SqlVar^.sqldata + 2, PChar(TempStr), Len);
end;
Блин, а немножко подумать ?
Хочется выругаться, но сдержусь 1 Если length(TmpStr)>SqlVar^.sqllen, то у тебя образаются данные. Так и задумано?
2 Зачем каждый раз перераспределять память, если SqlVar^.sqllen не изменяется ?
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
SQL_VARYING:
begin
TempStr := VarToStr(Value);
if SqlVar^.sqllen > length(TempStr) then
Len := length(TempStr)
else
Len := SqlVar^.sqllen;
ReallocMem(SqlVar.sqldata, SqlVar^.sqllen + 2);
PShort(SqlVar^.sqldata)^ := SqlVar^.sqllen;
StrLCopy(SqlVar^.sqldata + 2, PChar(TempStr), Len);
end;
КД>Блин, а немножко подумать ?
Я уже разные варианты пробоал, не получается . Если бы смог додумать не спрашивал бы, а уже давно сделал.
КД>1 Если length(TmpStr)>SqlVar^.sqllen, то у тебя образаются данные. Так и задумано?
Не понял вопроса?
КД>2 Зачем каждый раз перераспределять память, если SqlVar^.sqllen не изменяется ?
Это почему не меняется? По идее SqlVar^.sqldata изначально не расперделна т.е. равна nil, если же все таки она не равна nil т.е. память выделена то для этого и стоит перераспеределение памяти.
Вообще в связи с архитектурой компонентов для каждого запроса приходится создавать свой XSQLDA.
--
То, что вы уникальны еще не значит, что от вас есть толк