IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Bases de données Delphi Discussion :

[BDE & Delphi 2009] : je ne peux plus insérer de champ BLOB ?


Sujet :

Bases de données Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut [BDE & Delphi 2009] : je ne peux plus insérer de champ BLOB ?
    Bonjour à tous,

    Je dois passer une application Delphi7 en Delphi 2009. Le plus gros souci va concerner l'Unicode mais déjà je rencontre un problème sur l'insertion de valeurs binaires (type blob) en base de données.

    Nous utilisons le BDE avec le composant 'TQuery', en créant des requêtes paramétrées pour l'insertion de champ de type 'blob'. La contenu du paramètre est chargé via un appel à 'LoadFromStream' ou 'LoadFromFile'.
    Cela fonctionnait très bien sous Delphi 7, le type de donnée du paramètre était alors 'ftBlob' tandis que le contenu du variant sous-jacent (propriété 'Value') avait un type = 'varString'. La méthode 'AsBlob' du paramètre retournant le bon contenu (un 'string' contenant contenant les données du 'TStream' ou du fichier initial), la propriété Value retournant la même chose à une différence prêt : celui-ci est tronqué au premier caractère #0. Cela fonctionnait très bien (c'est le contenu retourné par 'AsBlob' qui était effectivement inséré en base de données).

    Depuis le passage à Delphi 2009 j'ai noté les différences suivantes avec le même code :
    - Le contenu du variant sous-jacent possède désormais le type 'Array of Byte'
    - La méthode 'AsBlob' retourne un TBytes (array of byte) correspondant au contenu du 'TStream' ou du fichier initial.
    - La propriété 'Value' retourne la même chose que 'AsBlob'.
    => tout semble donc être normal, étant donné le support de l'Unicode dans Delphi 2009 il semble logique que les méthodes de chargement de contenu binaire (LoadFromStream ou LoadFromFile) utilisent le type 'TBytes' (array of byte) plutôt que 'string'.

    ==> là où ça se gâte c'est qu'à l'exécution de la requête le contenu du paramètre n'est pas inséré en base de données, à la place mon champ contient '€€€€€€€€€€€€€€€€€€€....', bref un contenu corrompu.

    Je ne vois pas d'où cela peut provenir puisque ma requête est bien formulée ('Update License Set LICENSEDATA = :MYPARAM Where IDLICENSE = 19') et mon paramètre est correctement défini avant l'appel à ExecSQL. Et le code fonctionnait très bien sous Delphi 7.

    J'ai installé toutes les mises à jour possible de Delphi2009 mais cela n'a rien changé.

    Pouvez-vous m'aider à résoudre ce problème ? Merci !

  2. #2
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 086
    Par défaut
    Tu pourrais donner un exemple de code ?
    As-tu utilisé RawByteString à la place des anciens String si tu utilises AsString (ce qui est tout de même une vilaine tricherie)
    Ou as-tu systèmatiquement utilisé un Stream, ce qui est de loin la meilleure méthode !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Tu pourrais donner un exemple de code ?
    As-tu utilisé RawByteString à la place des anciens String si tu utilises AsString (ce qui est tout de même une vilaine tricherie)
    Ou as-tu systèmatiquement utilisé un Stream, ce qui est de loin la meilleure méthode !
    J'utilise systématiquement un TStream, voici la méthode qui est appelée pour créér le paramètre avant l'exécution de la requête d'insertion :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    function InternalAddParam( AQuery: TQuery; AFieldType: TDiaDBFieldType; const ParamName: string;
                               ParamValue: variant; AAutoClearParams: Boolean=False ): TParam;
    var
       MyStream: TMemoryStream;
    begin
       Assert( AQuery <> nil );
     
       if ( AAutoClearParams ) then begin
          AQuery.Params.Clear;
          Result:= nil;
     
       end else Result:= AQuery.Params.FindParam( ParamName );
     
       if ( Result = nil ) then
          Result:= AQuery.Params.CreateParam( DiaDBFieldTypeToFieldType( AFieldType ), ParamName, ptInput );
     
       Assert( Result <> nil );
     
       if ( AFieldType = ddbftBinary ) then begin
          MyStream:= TMemoryStream.Create;
          try
             GetDataAsStreamFromVariant( ParamValue, MyStream );
             Result.LoadFromStream( MyStream, ftBlob );
          finally
             MyStream.Free;
          end;
       end else Result.Value:= ParamValue;
    end;
    Pour information le contenu variant passé en argument est de type 'array of byte', si je passe par un stream lors de l'utilisation d'un champ binaire (ici 'ddbftBinary' est équivalent à 'ftblob') c'est parce-que sans cela sous Delphi7 le contenu du paramètre n'était pas bien affecté en utilisant directement 'Result.Value:= ParamValue;' (le variant obtenu était de type 'string' et les données situés après le premier #0 étaient tronquées). Ce qui ne semble d'ailleurs plus être le cas depuis Delphi 2009, mais j'ai laissé l'implémentation telle quelle pour le moment...

    Voici le code de l'exécution de la requête en elle-même :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
          AQuery.SQL.Text:= 'Insert Into LICENSE ( ' +
                            Cst_Bdd_LicenseCreationDate + ', ' +
                            Cst_Bdd_LicenseUserName + ', ' +
                            Cst_Bdd_LicenseData + ' ) Values ( ' +
                            Dts_FormatDateTime( FInsertDate ) + ', ' +
                            Dts_FormatString( AUserName ) + ', ' +
                            AddParamToQuery( AQuery, Cst_Bdd_LicenseData, VarValue,
                                             ddbftBinary, rbValue ) + ' )';
          // Pourquoi cela ne fonctionne-t-il pas ?
          // Le contenu du paramètre semble OK, la requête aussi, mais
          // son exécution me retourne un champ contenant que des '€€€€' sous
          // Delphi 2009 ???
          // Le même code fonctionne parfaitement sous Delphi 7...
          AQuery.ExecSQL;

  4. #4
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 086
    Par défaut
    Bon, tu as des fonctions et types persos Dia... cela n'aide pas à comprendre !
    Tu nous donne le code principale mais des fonctions comme GetDataAsStreamFromVariant reste obscure !

    Tu devrais repartir d'un cas simple !

    ParamValue est un variant, donc cela passe par une chaine, mais ta chaine de ton variant est ANSI ou UniCode ? Rien que de voir ça retire tout l'intérêt du Stream

    Comment appeles-tu InternalAddParam ? c'est dans AddParamToQuery ?
    Quelque chose t'empeche d'utiliser un TStream tout du long ?
    Comment est rempli VarValue ?
    VarValue était un array of byte, vérifie avec VarType() si c'est bien un array !
    Pourquoi ne pas avoir fait "Stream.Write(Bytes, Len)"

    c'est dommage de faire partiellement une requête paramètrée (série de + + +)!
    BDE = Paradox ??? tu ne peux pas insérer un BLOB en SQL, c'est dommage
    Car en Oracle, MySQL, PostGreSQL, avec un encodage Base64 tu peux insérer les BLOB directement dans un INSERT

    Pour le #0, logique en UniCode, il faut deux #0 pour indiquer la fin de chaine !
    D'où l'impression d'un meilleur fonctionnement !
    Ne jamais utiliser AsValue pour un Blobl ! Jamais !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Bon, tu as des fonctions et types persos Dia... cela n'aide pas à comprendre !
    Tu nous donne le code principale mais des fonctions comme GetDataAsStreamFromVariant reste obscure !

    Tu devrais repartir d'un cas simple !

    ParamValue est un variant, donc cela passe par une chaine, mais ta chaine de ton variant est ANSI ou UniCode ? Rien que de voir ça retire tout l'intérêt du Stream

    Comment appeles-tu InternalAddParam ? c'est dans AddParamToQuery ?
    Quelque chose t'empeche d'utiliser un TStream tout du long ?
    Comment est rempli VarValue ?
    VarValue était un array of byte, vérifie avec VarType() si c'est bien un array !
    Pourquoi ne pas avoir fait "Stream.Write(Bytes, Len)"

    c'est dommage de faire partiellement une requête paramètrée (série de + + +)!
    BDE = Paradox ??? tu ne peux pas insérer un BLOB en SQL, c'est dommage
    Car en Oracle, MySQL, PostGreSQL, avec un encodage Base64 tu peux insérer les BLOB directement dans un INSERT

    Pour le #0, logique en UniCode, il faut deux #0 pour indiquer la fin de chaine !
    D'où l'impression d'un meilleur fonctionnement !
    Ne jamais utiliser AsValue pour un Blobl ! Jamais !
    Merci de ta réponse ShaiLeTroll.

    Effectivement il manque le code de la fonction "AddParamToQuery" que voici :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function AddParamToQuery( AQuery: TQuery; const AFieldName: string;
                              const AParamValue: Variant;
                              AFieldType: TDiaDBFieldType; AReturnBind: TReturnBind;
                              AAutoClearParams: Boolean=False ): string;
    begin
       InternalAddParam( AQuery, AFieldType, Dts_GetBindField( AFieldName ),
                         AParamValue, AAutoClearParams );
     
       Result:= Dts_BindSign( AFieldName, AReturnBind );
    et 'Dts_BindSign' retourne le nom du paramètre précédé de ':'...

    Pour le reste j'ai en principe tout expliqué dans mes précédents posts :
    'TDiaDBFieldType' est une "pseudo-translation" TFieldType (traduit par la fonction 'DiaDBFieldTypeToFieldType') et 'ddbftBinary' est ainsi traduit en 'ftBlob'. C'est juste que le type 'TDiaDBFieldType' différencie certains type que ne fait pas 'TFieldType'...

    De même voici comment est affecté 'VarValue' :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
          CompressDataAsVariantFromStream( VarValue, Stream, DummyInt );
    Cette ligne précède l'appel à 'AQuery.SQL.Text:='... comme tu vois c'est encore une procédure, et je ne peux pas tout mettre car cela va commencer à faire un paquet de code et selon moi ce n'est pas pertinent.
    Je pense que l'important est de savoir que 'VarValue' contient un array of byte (j'ai évidemment vérifié le type via vartype = $2011 si mes souvenirs sont bons, enfin array of byte ça c'est sûr). Donc 'ParamValue' est également de ce type lors de l'appel et même, le paramètre retourné :
    sa propriété 'Value' est un variant de même type (array of byte).

    A partir de là je me dis que le paramètre est correctement défini et que ma requête devrait donc s'exécuter normalement non ?


    Petites précisions :

    Nos champs blobs en base de données ne contiennent que des données binaires (car contenu compressé), et c'est pourquoi nous utilisons le type qui semble le plus logique et "safe" : "array of byte". Notre application est multi-SGBD (Oracle, SQLServeur, MySQL mais aussi Access) et cela nous "interdit" (à moins de multiplier le code) les spécificités liées à l'utilisation de type "non générique" comme les champs BLOB en base de données. En l'occurrence j'ai effectué mon test sur une base de données de type Access.

    Il est vrai que c'est dommage de n'avoir qu'une requête semi-paramétré, mais dans le cas présent nous n'avons réellement pas besoin de performance, cette requête étant exécutée rarement. La paramètre découle donc simplement du choix de notre implémentation pour insérer des champs binaires en base de données.

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut
    Personne n'a été confronté à ce problème ? Cela m'étonne, et je ne vois pas comment trouver de solution simple et rapide.

    ...Je me vois déjà tout convertir en DBX, le truc qui va me prendre plus d'un mois... :-(... c'est quand même pas possible que ce soit un "bug" introduit dans Delphi 2009 (car je soupçonne que cela ait un rapport avec l'Unicode, bien qu'en principe je n'utilise pas le type "string" pour passer mes données binaires)

  7. #7
    Expert confirmé
    Avatar de Cl@udius
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2006
    Messages
    4 878
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 4 878
    Par défaut
    Salut
    Citation Envoyé par ZZZzzz2 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //...
       if ( AFieldType = ddbftBinary ) then begin
          MyStream:= TMemoryStream.Create;
          try
             GetDataAsStreamFromVariant( ParamValue, MyStream );
             Result.LoadFromStream( MyStream, ftBlob );
          finally
             MyStream.Free;
          end;
       end else Result.Value:= ParamValue;
    end;
    Est-ce qu'il ne manquerait pas un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MyStream.Seek(0, soFromBeginning);
    juste avant le LoadFromStream ?

    Question à tout hasard, sans savoir si celle-ci est pertinente.

    @+ Claudius.

  8. #8
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 086
    Par défaut
    Tu as oublié de founir
    GetDataAsStreamFromVariant
    CompressDataAsVariantFromStream

    tu nous sors des fonctions que tu as développé !
    Et plus on avance, et plus tu nous en donne de nouvelles !

    Et c'est juste le passage Variant (2011 array of WordBool) vers Stream qui est interressant, imagine qu'en 2009, CodeGead a changé l'implémentation des structures TVarData et TVarRec (qui ne sont pas compatible évidemment )

    le mieux est de vérifier proprement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if VarIsType(V1, varArray or varByte) then
    Sinon, lorsque l'on n'utilise que des Stream pour manipuler les Blobs sans passer par des variants, on a pas ces problèmes, c'est juste une uzinagaz ton truc !

    Perso, j'utilisais aussi une compression mais toujours en Stream !
    Le MemoryStream n'étant qu'une zone mémoire, c'est très polyvalent, il est vrai qu'un array of byte est assez proche !


    @Cl@udius, ben oui, c'est pour cela que je voulais le code de GetDataAsStreamFromVariant, j'ai pensé au bon vieux seek 0 mais son code fonctionne en D7 mais plus en 2009, qui laisse supposer un problème de taille du char (et par conséquent taille de buffer)

    Perso, j'ai souvent une option AutoRewind (défaut à true) dans mes Fonctions d'écriture dans les Stream !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Tu as oublié de founir
    GetDataAsStreamFromVariant
    CompressDataAsVariantFromStream

    tu nous sors des fonctions que tu as développé !
    Et plus on avance, et plus tu nous en donne de nouvelles !

    Et c'est juste le passage Variant (2011 array of WordBool) vers Stream qui est interressant, imagine qu'en 2009, CodeGead a changé l'implémentation des structures TVarData et TVarRec (qui ne sont pas compatible évidemment )

    le mieux est de vérifier proprement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if VarIsType(V1, varArray or varByte) then
    Sinon, lorsque l'on n'utilise que des Stream pour manipuler les Blobs sans passer par des variants, on a pas ces problèmes, c'est juste une uzinagaz ton truc !

    Perso, j'utilisais aussi une compression mais toujours en Stream !
    Le MemoryStream n'étant qu'une zone mémoire, c'est très polyvalent, il est vrai qu'un array of byte est assez proche !


    @Cl@udius, ben oui, c'est pour cela que je voulais le code de GetDataAsStreamFromVariant, j'ai pensé au bon vieux seek 0 mais son code fonctionne en D7 mais plus en 2009, qui laisse supposer un problème de taille du char (et par conséquent taille de buffer)

    Perso, j'ai souvent une option AutoRewind (défaut à true) dans mes Fonctions d'écriture dans les Stream !

    Voici les fonctions en question :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    procedure GetDataAsStreamFromVariant(const Data: variant; AStream: TStream);
    var
       p: Pointer;
       len: Integer;
    begin
       Assert( AStream <> nil );
     
       // len:= VarArrayHighBound(Data, 1);
       len:= Succ( VarArrayHighBound(Data, 1) );
     
       // on copie les données dans le tableau
       p:= VarArrayLock(Data);
       try
          AStream.Position:= 0;
          AStream.WriteBuffer(p^, len);
       finally
          VarArrayUnlock(Data);
       end;
    end;

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    function CompressDataAsVariantFromStream(var Data: variant; AStream: TStream;
                                             out CompressedDataSize: Int64;
                                             Verbose: Boolean=False): boolean;
    var
       CompressedFile: TMemoryStream;
    begin
       CompressedFile:= TMemoryStream.Create;
       try
          // Comme la fonction retourne 'False' en cas d'échec il ne
          // faut pas qu'on puisse générer des exceptions
          try
             Compress( AStream, CompressedFile );
             CompressedDataSize:= CompressedFile.Size;
             Data:= GetDataAsVariantFromStream( CompressedFile );
             Result:= True;
          except
             On E: EZlibError do begin
                Result:= False;
                if ( Verbose ) then MessageDlgFront( 'Exception "'+E.ClassName+'" lors de l''appel "U_VarTools.CompressDataAsVariantFromStream".'+sLineBreak+
                                                     'Message d''erreur = "'+( E.Message )+'"', mtError )
             end;
          end;
       finally
          CompressedFile.Free;
       end;
    end;

    et comme tu vas me le demander voici une dernière :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    function GetDataAsVariantFromStream(AStream: TStream): variant;
    var
       p: Pointer;
       len: integer;
    begin
       Assert( AStream <> nil );
     
       // par défaut on initialise toujours le tableau avec un seul élément = 0
       result:= GetEmptyVarArray(VarByte);
     
       len:= AStream.Size;
       // Il faut faire le test '>=' afin de gérer le cas des tableaux sans élément
       if (len >= 0) then begin
          VarArrayRedim(Result, Pred( len ));
     
          // on copie les données dans le tableau
          p:= VarArrayLock(Result);
          try
             AStream.Position:= 0;
             AStream.ReadBuffer(p^, len);
          finally
             VarArrayUnlock(Result);
          end;
       end;
    end;



    Enfin vous vous attardez sur la gestion des TStream qui rend le tout confus, je l'avoue, et c'est la raison pour laquelle je n'avais pas mis le code source car de mon point de vue le problème ne provient pas de là puisque le contenu du Variant résultant est correcte.

    Preuve en est, j'ai modifié ma fonction de départ comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    function InternalAddParam( AQuery: TQuery; AFieldType: TDiaDBFieldType; const ParamName: string;
                               ParamValue: variant; AAutoClearParams: Boolean=False ): TParam;
    begin
       Assert( AQuery <> nil );
     
       if ( AAutoClearParams ) then begin
          AQuery.Params.Clear;
          Result:= nil;
     
       end else Result:= AQuery.Params.FindParam( ParamName );
     
       if ( Result = nil ) then
          Result:= AQuery.Params.CreateParam( DiaDBFieldTypeToFieldType( AFieldType ), ParamName, ptInput );
     
       Assert( Result <> nil );
     
       // Depuis Delphi 2009 et le support de l'unicode il n'y a plus besoin de
       // passer par 'TParam.LoadFromStream' pour que celui-ci contienne bien
       // le contenu du tableau d'octets via 'AsBlob'. Je me contente d'une
       // affectation directe :
       Result.Value:= ParamValue;
    end;

    Et bien sûr le résultat est identique ! Désolé, j'aurai peut-être du commencer par là (on aurait gagné du temps) mais je ne voulais pas modifié mon ancienne implémentation trop rapidement...

    Désolé si je paraît dédaigneux dans mes réponses, en réalité je réponds vite, et je peux manquer (mais c'est involontaire) de courtoisie...

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 149
    Par défaut
    Citation Envoyé par Cl@udius Voir le message
    Salut


    Est-ce qu'il ne manquerait pas un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MyStream.Seek(0, soFromBeginning);
    juste avant le LoadFromStream ?

    Question à tout hasard, sans savoir si celle-ci est pertinente.

    @+ Claudius.
    [Edit] je n'avais pas bien lu ton post, en fait un 'LoadFromStream' remet à 0 le stream passé en argument, donc c'est inutile :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    procedure TMemoryStream.LoadFromStream(Stream: TStream);
    var
      Count: Longint;
    begin
      Stream.Position := 0;
      Count := Stream.Size;
      SetSize(Count);
      if Count <> 0 then Stream.ReadBuffer(FMemory^, Count);
    end;

  11. #11
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 086
    Par défaut
    Tout dépend du code de GetDataAsStreamFromVariant et du mystérieux CompressDataAsVariantFromStream
    Cette fonction étant entre le Create et le LoadFromFile, comme on ne connait pas son contenu, la remarque de Cl@udius est tout à fait pertinente et ta réponse nous amène à deux possibilités :
    - Tu connais le code et donc tu sais qu'il n'y a pas de problème à ce sujet
    - Tu as trop la tête dans le guidon pour remarquer le détail qui tue !

    Si tu utilises dedans un Write pour écrire le Variant, la Position dans le Stream change après le Write !
    D'où la necessité de faire un Rewind !
    Mais comme ton code fonctionnait en D7, cela doit déjà le gérer !

    Tu poses des Questions ZZzzzz mais tu ne réponds pas aux notre, tout ne nous donne pas les élements utiles et tu balayes nos remarques d'un revert Dédaigneux ! C'est un peu lassant !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

Discussions similaires

  1. Réponses: 2
    Dernier message: 04/10/2014, 18h02
  2. [phpMyAdmin] Je ne peux plus insérer des données après avoir renommé une table!
    Par yvessavoie dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 1
    Dernier message: 14/02/2014, 16h22
  3. Delphi 2009 plus lent que Delphi 5
    Par portu dans le forum EDI
    Réponses: 0
    Dernier message: 30/09/2009, 10h50
  4. Réponses: 0
    Dernier message: 23/04/2009, 09h38
  5. [IB71] Je ne peux plus supprimer mes foreign key...
    Par BoeufBrocoli dans le forum InterBase
    Réponses: 3
    Dernier message: 19/09/2003, 14h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo