Interbase SQL_TEXT & SQL_VARYING проблемы
От: Sergey Merkuriev  
Дата: 28.04.03 06:15
Оценка:
Hello All.

Есть тарблема с 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
Далее выполняю
isc_dsql_execute(@FStatusVector, @FTrHandle,
          @FStmtHandle, FDialect, FParamSqlData);


При проверке FStatusVector получаю ошибку:

"Sql error: Dynamic SQL error. Error: -804. An error found in the application input parameter for the SQL statement.


Если убрать текстовый параметр/поле — "name" все работает отлично. я думаю что проблема с заполнением SqlVar^.sqldata для текстовых полей.

Примечание: Мои компоненты работают нормально с простымим запросами (без параметров) возвращают все данные корректно. Проблема заключается в запросах с параметрами.
--
То, что вы уникальны еще не значит, что от вас есть толк
Re: Interbase SQL_TEXT & SQL_VARYING проблемы
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 28.04.03 06:25
Оценка:
Здравствуйте, 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
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re: Interbase SQL_TEXT & SQL_VARYING проблемы
От: mrhru Россия  
Дата: 28.04.03 06:33
Оценка:
Здравствуйте, 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);

тогда остальные манипуляции должны сработать.
Re[2]: Interbase SQL_TEXT & SQL_VARYING проблемы
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 28.04.03 06:41
Оценка: 9 (1)
Здравствуйте, mrhru, Вы писали:

M>Я думаю, надо различать случаи SQL_TEXT и SQL_VARYING

M>Когда тип SQL_TEXT, то строка задаётся нулём в конце, когда SQL_VARYING — то первые два байта
M>это длина строки.

В обоих случаях терминальный нулевой символ не используется.
Для SQL_TEXT длина строки определяется из XSQLVAR::sqllen

Плавали — знаем. Очень удивлюсь если это не так

Терминальные нули используются в массивах IB.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[3]: Interbase SQL_TEXT & SQL_VARYING проблемы
От: mrhru Россия  
Дата: 28.04.03 06:59
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

M>>Я думаю, надо различать случаи SQL_TEXT и SQL_VARYING

M>>Когда тип SQL_TEXT, то строка задаётся нулём в конце, когда SQL_VARYING — то первые два байта
M>>это длина строки.

КД>В обоих случаях терминальный нулевой символ не используется.

КД>Для SQL_TEXT длина строки определяется из XSQLVAR::sqllen

КД>Плавали — знаем. Очень удивлюсь если это не так


Да, совершенно верно, не используются!

КД>Терминальные нули используются в массивах IB.
Re[2]: Interbase SQL_TEXT & SQL_VARYING проблемы
От: Sergey Merkuriev  
Дата: 28.04.03 09:17
Оценка:
Здравствуйте, Дмитрий, Вы писали:

Для начала, что касается SQL_VARYING

Сделал так как ты говоришь:

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;

не работатет
--
То, что вы уникальны еще не значит, что от вас есть толк
Re[3]: Interbase SQL_TEXT & SQL_VARYING проблемы
От: mrhru Россия  
Дата: 28.04.03 09:40
Оценка:
Здравствуйте, Sergey Merkuriev, Вы писали:

SM>Сделал так как ты говоришь:


SM>SQL_VARYING:
SM>

SM>     begin
SM>       TempStr := VarToStr(Value);
SM>       if SqlVar^.sqllen > length(TempStr) then
SM>         Len := length(TempStr)
SM>       else Len := SqlVar^.sqllen;

после препарирования, в SqlVar^.sqllen храниться максимальная длина поля!!!
которую надо запомнить и использовать при последующих присвоениях

надо указывать полную длину, выделенную под SqlVar.sqldata
SqlVar^.sqllen := length(TempStr) + 2;


SM>       ReallocMem(SqlVar.sqldata, SqlVar^.sqllen + 2);
SM>       PShort(SqlVar^.sqldata)^ := SqlVar^.sqllen;
SM>       StrLCopy(SqlVar^.sqldata + 2, PChar(TempStr), Len);
SM>     end;
SM>   SQL_TEXT:
SM>     begin
SM>       TempStr := VarToStr(Value);
SM>       if SqlVar^.sqllen > length(TempStr) then
SM>         Len := Length(TempStr)
SM>       else Len := SqlVar^.sqllen;


SqlVar^.sqllen := length(TempStr); // здесь надо надо указать длину самой строки


SM>       ReallocMem(SqlVar^.sqldata, SqlVar^.sqllen + 1);
SM>       StrLCopy(SqlVar^.sqldata, Pchar(TempStr), Len);
SM>     end;
SM>

Имхо
Re[4]: Interbase SQL_TEXT & SQL_VARYING проблемы
От: Sergey Merkuriev  
Дата: 28.04.03 09:57
Оценка:
Здравствуйте, mrhru, Вы писали:

Я cделал след образом:

SQL_VARYING, SQL_TEXT:
   begin
      if SqlVar^.sqllen > length(TempStr) then
          SqlVar^.sqllen := length(TempStr);
       SqlVar^.sqltype := SQL_TEXT;
       ReallocMem(SqlVar^.sqldata, SqlVar^.sqllen);
       Move(TempStr[1], SqlVar^.sqldata^, SqlVar^.sqllen);
   end;

Этот пример приводился в ApiGuide. Теперь все работает ().

Вариант же который ты советуешь ниже упорно не хочет работать. Можеть написать правильный код?
--
То, что вы уникальны еще не значит, что от вас есть толк
Re[5]: Interbase SQL_TEXT & SQL_VARYING проблемы
От: mrhru Россия  
Дата: 28.04.03 10:03
Оценка:
Здравствуйте, Sergey Merkuriev, Вы писали:

SM>Этот пример приводился в ApiGuide. Теперь все работает ().


SM>Вариант же который ты советуешь ниже упорно не хочет работать. Можеть написать правильный код?


Гм, извиняюсь. Я, собственно приведенный вариант (из API) и использую.
Т.е. присвоение через SQL_TEXT.
Re[3]: Interbase SQL_TEXT & SQL_VARYING проблемы
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 28.04.03 10:17
Оценка:
Здравствуйте, Sergey Merkuriev, Вы писали:

Спасибо той доброй душе, которая отформатировала текст

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 не изменяется ?
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[4]: Interbase SQL_TEXT & SQL_VARYING проблемы
От: Sergey Merkuriev  
Дата: 28.04.03 11:14
Оценка:
Здравствуйте, Дмитрий, Вы писали:

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.
--
То, что вы уникальны еще не значит, что от вас есть толк
Re[5]: Interbase SQL_TEXT & SQL_VARYING проблемы
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 28.04.03 11:31
Оценка:
Здравствуйте, Sergey Merkuriev, Вы писали:

Так. Давая сделаем перекур. Вот реализация установки SQL_TEXT и SQL_VARYING соответственно.
Он немного многословная, но точно рабочая.

// ------------------- char ----------------------------------------------
string ib_xsqlda::set_char(size_type index,const string& text,bool null)
{
 VALIDATE_INDEX(index,"set_char");

 assert(m_data!=NULL);
 XSQLVAR* pvar=&m_xsqlda->sqlvar[index];

 pvar->sqlscale  =0;
 pvar->sqltype   =SQL_TEXT|1;

 //проводим инициализацию на случай сбоя получения памяти -----------
 pvar->sqlind    =NULL;
 pvar->sqldata   =NULL;
 pvar->sqllen    =0;

 //выделение памяти -------------------------------------------------
 sql_size_type   sqllen=(sql_size_type)min((string::size_type)numeric_limits<sql_size_type>::max(),
                                           text.length()); //размер буфера

 pvar->sqlind    =m_data->get_ind(index);
 pvar->sqldata   =m_data->allocate_data(index,sqllen);
 pvar->sqllen    =sqllen;

 //установка данных -------------------------------------------------
 *(pvar->sqlind) =null?short(-1):short(0);

 CHECK_WRITE_PTR(pvar->sqldata,sqllen);//допустимость записи
 memcpy(pvar->sqldata,text.begin(),sqllen);

 return text;
}//set_char

// ------------------- varchar -------------------------------------------
void ib_xsqlda::set_varchar_0(size_type index,const char* str,size_type str_len,bool null)
{
 VALIDATE_INDEX(index,"set_varchar");

 XSQLVAR* pvar=&m_xsqlda->sqlvar[index];

 pvar->sqlscale=0;
 pvar->sqltype =SQL_VARYING|1;

 if(str==NULL)
  str_len=0;
 else
 if(str_len==-1)
  str_len=strlen(str);

 CHECK_READ_PTR(str,str_len);

 //инициализация на случай сбоя -------------------------------------
 pvar->sqlind   =NULL;
 pvar->sqldata  =NULL;
 pvar->sqllen   =0;

 //выделение памяти под данные --------------------------------------
 sql_size_type sqllen=(short)min((size_type)SHRT_MAX-2,str_len);

 pvar->sqlind  =m_data->get_ind(index);
 pvar->sqldata =m_data->allocate_data(index,sqllen+2);
 pvar->sqllen  =sqllen;

 //установка данных -------------------------------------------------
 *(pvar->sqlind)=null?short(-1):short(0);

 CHECK_WRITE_PTR(pvar->sqldata,sqllen+2);
 *reinterpret_cast<short*>(pvar->sqldata)=sqllen; //длина записанной строки

 memcpy(pvar->sqldata+2,str,sqllen);
}//set_varchar_0
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.