Конференция "Базы" » Incorrect values within SQLDA structure при выполнении запроса [D7, IB6.x]
 
  • pushkin42 © (04.11.08 19:53) [0]
    Есть вот функция такая:  (D2007, FB2, dbExpress):

    function TSQLDatabaseThread.SelectSQLA(const Q: String; const ParamNames,
     ParamValues: array of Variant): TSQLDataSet;

    var Command: String;
       PNI, PNC: Integer;

     function ParamType(const Param: Variant): Byte;
     var basicType: TVarType;
     begin
       basicType := VarType(Param) and VarTypeMask;

       case basicType of
         varEmpty     : Result := VT_EMPTY;
         varNull      : Result := VT_NULL;
         varSmallInt  : Result := VT_SMALLINT;
         varInteger   : Result := VT_INTEGER;
         varSingle    : Result := VT_SINGLE;
         varDouble    : Result := VT_DOUBLE;
         varCurrency  : Result := VT_CURRENCY;
         varDate      : Result := VT_DATE;
         varBoolean   : Result := VT_BOOL;
         varVariant   : Result := VT_VARIANT;
         varUnknown   : Result := VT_UNKNOWN;
         varByte      : Result := VT_BYTE;
         varWord      : Result := VT_WORD;
         varLongWord  : Result := VT_WORD;
         varInt64     : Result := VT_INT64;
         varStrArg    : Result := VT_STRING;
         varString    : Result := VT_STRING;
         varAny       : Result := VT_ANY;
         varTypeMask  : Result := VT_TYPEMASK;
         else Result := VT_UNKNOWN;
       end;
     end;
    begin
     // выполнение запроса (определение автоматическое)
     Result := TSQLDataSet.Create(nil);

     if Connection.Connected=False then begin
       Connection.Connected := True;
     end;

     Result.SQLConnection := Connection;

     Result.ParamCheck := (Length(ParamNames)<>0);

     //try
       Result.CommandText := Q;
       Command := Parse(Q, #32, 1);

    //    Result.Params := TParams.Create(Result);
       Result.Params.Clear;
       Result.Close;

       if Length(ParamNames)<>0 then begin
       // перечисление параметров
         PNC := Length(ParamNames)-1;  // количество параметров
         for PNI := 0 to PNC do begin
           case ParamType(ParamValues[PNI]) of
             VT_UNKNOWN,
             VT_NULL        : Result.Params.CreateParam(ftUnknown, ParamNames[PNI], ptInputOutput);

             VT_SMALLINT    : Result.Params.CreateParam(ftSmallInt, ParamNames[PNI], ptInputOutput);
             VT_INTEGER,
             VT_SINGLE      : Result.Params.CreateParam(ftInteger, ParamNames[PNI], ptInputOutput);
             VT_DOUBLE      : Result.Params.CreateParam(ftFloat, ParamNames[PNI], ptInputOutput);
             VT_CURRENCY    : Result.Params.CreateParam(ftCurrency, ParamNames[PNI], ptInputOutput);
             VT_DATE        : Result.Params.CreateParam(ftDate, ParamNames[PNI], ptInputOutput);
             VT_BOOL        : Result.Params.CreateParam(ftBoolean, ParamNames[PNI], ptInputOutput);
             VT_VARIANT     : Result.Params.CreateParam(ftVariant, ParamNames[PNI], ptInputOutput);
             VT_BYTE        : Result.Params.CreateParam(ftFloat, ParamNames[PNI], ptInputOutput);
             VT_WORD,
             VT_LWORD       : Result.Params.CreateParam(ftWord, ParamNames[PNI], ptInputOutput);
             VT_INT64       : Result.Params.CreateParam(ftInteger, ParamNames[PNI], ptInputOutput);
             VT_STRARG,

             VT_STRING      : Result.Params.CreateParam(ftString, ParamNames[PNI], ptInputOutput);

             VT_ANY         : Result.Params.CreateParam(ftVarBytes, ParamNames[PNI], ptInputOutput);
             VT_TYPEMASK    : Result.Params.CreateParam(ftUnknown, ParamNames[PNI], ptInputOutput);

             else
                              Result.Params.CreateParam(ftVariant, ParamNames[PNI],
                              ptUnknown);
           end;
           Result.Params.ParamByName(ParamNames[PNI]).AsString :=
           String(ParamValues[PNI]);
         end;
       end;

       if (Command='SELECT') then begin
         Result.Open
       end else begin
         Result.ExecSQL();
         FinalizeSQL(Result);
       end;
     {
     except
       Result.Close;
       Result.Free;
       Exit(nil);
     end;
     }

    end;



    Почему-то если параметрами подсунуть скажем ['uid', 3] то выполняется нормально и возвращает датасет. А вот если подсунуть скажем ['uname', 'какая_то_строка'], выдает "Incorrect values within SQLDA structure". ParamCheck := False не помогло.

    Где могут быть грабли?
  • Johnmen © (04.11.08 20:03) [1]
    Можно поинтересоваться, зачем все эти танцы нужны?
    И почему для ФБ используется дбЕкспресс?
  • pushkin42 © (04.11.08 20:10) [2]
    Танцы... для универсализации, наверное. Мне удобнее написать один раз функцию, выполняющую все виды запросов, и потом приспособить ее под отдельные цели вида ExecSQL(Query) и SelectSQL(Query).

    Используется dbExpress потому, что по вынужденным причинам пересел на Tiburon, в котором IB компоненты нещадно глючат (видимо, сырые), а это оказались единственные компоненты, которые работают. FIB и иже с ними покупать не хочу - пишу для себя - дорого...
  • Johnmen © (04.11.08 20:17) [3]

    >  для универсализации, наверное. Мне удобнее написать один
    > раз функцию, выполняющую все виды запросов,

    Это бесперспективное заблуждение...

    А по сути:
    - приводи сам запрос,
    - дбЕкспресс весьма специфичен, попытки на его основе что-то "универсализировать" за рамками работы с MySQL, обречены на провал,
    - данное сообщение означает, что функция клиентской длл не смогла выделить и заполнить область параметров.
  • pushkin42 © (04.11.08 20:20) [4]
    А что вы можете предложить "в рамках" решения данного вопроса? Я не хочу использовать специфичный софт и компоненты, я часто пишу OpenSource, и часто пишу в команде (всем не поставишь). Возвращаться на Delphi 7 не хочу.
  • Johnmen © (04.11.08 20:32) [5]
    Лично я бы не гнался за "универсализацией". В данном случае мы же заранее знаем вид запроса, а значит и количество и качество параметров...
    Для получения наборов данных - одни компоненты, для выполнения остальных запросов - другие. А вид запроса меняй наздоровье в рантайме.
    И параметры будут создаваться "на лету" неявно. Останется только их определить в цикле по элементам открытого массива.
  • Правильный$Вася (04.11.08 20:52) [6]

    > дбЕкспресс весьма специфичен, попытки на его основе что-
    > то "универсализировать" за рамками работы с MySQL, обречены
    > на провал,

    весьма смелое утверждение, надо признать

    > Мне удобнее написать один раз функцию, выполняющую все виды
    > запросов, и потом приспособить ее под отдельные цели вида
    > ExecSQL(Query) и SelectSQL(Query).

    имхо, излишне
  • Johnmen © (04.11.08 21:25) [7]

    > весьма смелое утверждение, надо признать

    Да, смелое, согласен.
    Если у кого-то будут подтвержденные противоположные мнения - с удовольствием выслушаю.
  • PEAKTOP © (05.11.08 12:45) [8]
    > Johnmen ©   (04.11.08 21:25) [7]
    > Если у кого-то будут подтвержденные противоположные мнения - с удовольствием выслушаю.


    Не будет.
    Сколько народ не учи, что быстрее чем через API и ручное управление транзакциями ничего нет. Все равно не понимают: то труп BDE где-то выкопают, то dbExpress, то ODBC. Нет, конечно, я понимаю кодеров на M$VC, Java - им деваться некуда от этих прослоек, да и самому из 1C коннектиться через ODBC приходилось. Но если ты пишешь на Delphi, нахрена лезть то в эти дебри ? Тот же IBX, хоть он и кривой на всю голову, но при определенном привыкании к глюкам позволяет нормально писать.
  • Правильный$Вася (05.11.08 14:19) [9]

    > Тот же IBX, хоть он и кривой на всю голову, но при определенном
    > привыкании к глюкам позволяет нормально писать.

    а вот dbx для IB вовсе не кривой и ни к каким глюкам привыкать не нужно
    или нужно стать любителем кошерных компонентов, чтоб хвастаться своим любимым, но страшным способом?
  • GRAND © (05.11.08 14:30) [10]

    > FIB и иже с ними покупать не хочу - пишу для себя - дорого.
    > ..


    Все же стоило бы поискать по нышпоркам, ИМХО - для IB/FB/YA человечество ничего лучшего не изобрело.


    > кривой на всю голову


    - это можно сказать обо всем, кроме фибов, что вы попытаетесь так или иначе приспособить под FB.
  • PEAKTOP © (05.11.08 16:46) [11]
    > - это можно сказать обо всем, кроме фибов, что вы попытаетесь так или иначе приспособить под FB.

    Никто уже давно не пытается :)

    У половины людей из FirebirdFoundation самописные библиотеки. В том числе и у Сергея Бузаджи. По последней скажу: не кошерно это использовать в потомке TDataSet (имеющем пять действий Select, Refresh, Insert, Update, Delete) две транзакции -  это годится только для студенческих курсовых, потому как практика в некоторых случаях заставляет использовать пять транзакций с разными параметрами. Поэтому у большинства людей пяти-транзакционные библиотеки.

    Я свою писал на базе IBX от Delphi7. Конечно, пришлось обработать напильником, в некоторых местах - резал болгаркой и "приваривал". :) Зато не страдал фигней, и в процессе создания ни разу не пытался в отладчике выловить багу в говнокоде, к коему я причисляю FIBPlus, несмотря на его стабильность. IBX тоже не страдает чистотой кода, непонятно вообще, как Borland/CodeGear/Embarcadero выпустили это в продажу на фоне кода самой VCL. Наверное, чтобы потребители прочувствовали разницу ? :)
  • GRAND © (05.11.08 17:20) [12]

    > потому как практика в некоторых случаях заставляет использовать
    > пять транзакций с разными параметрами. Поэтому у большинства
    > людей пяти-транзакционные библиотеки.


    Нет, я такого авангардизма не понимаю :))) Интересно было бы ознакомиться с каким-нибудь примером острой необходимости пятитранзакционного датасета, ибо даже моя извращенная фантазия вряд ли подобное сможет породить.

    Обработанный напильником IBX - это агхиинтересно, конечно. Но до какой степени можно обрабатывать это "чудо" напильником, если там сама фундаментальная идеология уже на старте во многом проигрывает фибам? Может, просто лучше правильно юзать фибы? ;)
  • PEAKTOP © (05.11.08 18:24) [13]
    >GRAND ©   (05.11.08 17:20) [12]
    > Но до какой степени можно обрабатывать это "чудо" напильником, если там сама фундаментальная идеология уже на старте во многом проигрывает фибам? Может, просто лучше правильно юзать фибы? ;)


    Филосфия IBX = Философия TDataSet = Философия FIBPlus, также  = моя библиотека. Потому, как только так и не иначе, если Вы хотите увидеть Ваш набор данных в TDBGrid и проч. До какой степени ? - Наверное, пока камня на камне не останется :)

    Фундаментально - философия IBX проигрывает:
    1)  В подключениях. У меня может быть более чем одна клиентская библиотека доступа, в том числе и к устаревшему InterBase, и Embedded Firebird, с помощью которой я подгружаю данные из "БазыУдаленогоФилиала" в "ЦентральнуюБазу", которая где-то-там...
    2) В транзакциях наборов данных. По минимуму - две (что уже есть в FIBPlus), по правильному - пять.

    > Интересно было бы ознакомиться с каким-нибудь примером острой необходимости пятитранзакционного датасета, ибо даже моя извращенная фантазия вряд ли подобное сможет породить.

    Видимо, у Вас не по настоящему извращенная фантазия :)
    -----------------------
    Кстати, камень в огород IBX и FIBPlus. Попробуете сделать INSERT в наборе данных, потом Post набора данных, а потом - Update этой же самой (только что вставленной) записи и ее же Post. А потом посмотрите, какая версия сохранится. :)

    Вот и я говорю - пять транзакций....
  • GRAND © (05.11.08 20:52) [14]

    > Филосфия IBX = Философия TDataSet = Философия FIBPlus, также
    >  = моя библиотека


    А что тогда есть философия чуть более высокого уровня - TTable? ;) Вот тут-то мы и приходим к кардинальному различию: в FIBPlus этого уродство отсутствует.


    > Кстати, камень в огород IBX и FIBPlus. Попробуете сделать
    > INSERT в наборе данных, потом Post набора данных, а потом
    > - Update этой же самой (только что вставленной) записи и
    > ее же Post. А потом посмотрите, какая версия сохранится.
    >  :)


    Проверил: последняя (проапдейченная) версия. Как и должно быть. Собственно, я здесь проблем не вижу вот по какой причине: пять операций с датасетами (Select, Refresh, Insert, Update, Delete) прекрасно делятся на читающие и пишущие. Первые две работают в читающей транзакции, остальные три - в пишущей. Я не вижу чего-то непреодолимого, что может заставить Select и Refresh работать в разных транзакциях, а также Insert, Update и Delete. Более того, смысла я этом тоже не вижу ;)
 
Конференция "Базы" » Incorrect values within SQLDA structure при выполнении запроса [D7, IB6.x]
Есть новые Нет новых   [134477   +39][b:0][p:0.003]