PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 24/06/2010 12:03:09

Fooshi
Membre

Probleme de message Parse

Bonjour,
En C j'essaye d'envoyer une commande 'Parse' a un serveur PostgreSQL .

Dans mon cas à moi, je selectionne une instruction préparée non nommée (chaine vide donc), nombre de types de donnée de paramètres spécifiés = 0 codé sur 16 bits donc.

j'ai donc codé une fonction pour réaliser cette commande Parse, qui m'enregistre dans un buffer la chaine suivante :

'P00073 SELECT intval, floatval, strval FROM test_sqlclient WHERE name=$1;00 '

P = Marqueur de commande 'Parse'
00073 = 4 octets qui indiquent la taille
00 = Nombre de types de données de paramètre spécifiés (a la fin aprés le point virgule)

Je vous donne ma fonction en C :

/* Construct the 'Parse' message    */
    do
    {
        msg_len = 0;
        IF (msg)        memcpy(msg + msg_len, "", 1);                // An empty string selects the non-prepared statement named.
        msg_len += 1;
        IF (msg)        memcpy(msg + msg_len, query, strlen(query));// Query string TO analyse.
        msg_len += strlen(query);
        IF (count > 0 && paramtypes)
        {
            IF (msg)    sql_put_int(sizeof(int16), count, msg + msg_len);       
            msg_len += sizeof(int16);
            FOR (i=0; i<count; i++)
            {
                IF (msg)sql_put_int(sizeof(int32), paramtypes[i], msg + msg_len);// Object ID of the DATA type of the parameter.
                msg_len += sizeof(int32);
            }
        }
        else
        {
            IF (msg)    sql_put_int(sizeof(int16), 0, msg + msg_len);            // Many types of DATA specified parameter.
            msg_len += sizeof(int16);
        }
        IF (msg) break;   
        msg = (char *) malloc(msg_len);
    }
    while(msg);

    FOR (i=0; i<msg_len; i++)
    fprintf(stdout,"%c",msg[i]);
   
    sql_send_msg(sql_conn, 'P', msg_len, msg);

La fonction sql_send_msg ajoute le message type 'P' , puis la taille calculée (taille du message + taille elle meme"), puis le message.

C'est un probleme un peu special que j'ai l'a (developper un client postgrsql sans lib) mais je bloque pas mal et je vois pas ou est le probleme (j'ai presque fais un copier coller de la libpq bibliotheque de postgresql)

Merci d'avance en tout ca

Hors ligne

#2 24/06/2010 12:26:28

Marc Cousin
Membre

Re : Probleme de message Parse

Bonjour,

Sans commentaire, ce code est assez incompréhensible.
D'entrée, je bloque sur :
  msg_len = 0;
        IF (msg)        memcpy(msg + msg_len, "", 1);                // An empty string selects the non-prepared statement named.
        msg_len += 1;
        IF (msg)        memcpy(msg + msg_len, query, strlen(query));// Query string TO analyse.

Il n'y a aucune raison que ça marche :
Vous copiez une chaine vide (aucun caractère, suivi d'un \0, donc juste un \0) dans msg, sur 1 octet, via le memcpy. Donc vous forcez msg à  \0. Peu de chance ensuite pour que le second if(msg) serve à quelque chose.

D'où vient ce code ? C'est un copier-coller, comme vous l'avez dit ? d'où provient-il et avez vous compris comment il fonctionne ?


Marc.

Hors ligne

#3 24/06/2010 13:27:29

gleu
Administrateur

Re : Probleme de message Parse

Si je comprends bien, le code vient de la libpq. Et ma question est : mais pourquoi vouloir refaire ce que fait déjà (et bien) la libpq ?


Guillaume.

Hors ligne

#4 24/06/2010 14:33:03

Fooshi
Membre

Re : Probleme de message Parse

@Marc cousin : Effectivement je force une chaine vide mais pas '\0', le 2 eme memcpy fonctionne tres bien d'ailleurs. Ce code vient de moi mais je m'inspire des fonctions de la libpq pour construire les messages et oui je comprend trés bien comment il fonctionne.

@gleu : Car mon chef de projet et moi avons développé des fonctions de requetes TCP et de gestion memoire (Double liste chainée de block pool notament) plus efficace que la libpq selon mon chef de projet et que je rajoute en ce moment la couche de communication du client PostgreSQL.

Apres avoir modifié mon code comme ceci :


do
    {
        msg_len = 0;
        if (msg)        memcpy(msg + msg_len, "", 1);                // An empty string selects the non-prepared statement named.
        msg_len += 1;
        if (msg)        memcpy(msg + msg_len, query, strlen(query));// Query string to analyse.
        msg_len += strlen(query) + 1;
        if (count > 0 && paramtypes)
        {
            if (msg)    sql_put_int(sizeof(int16), count, msg + msg_len);       
            msg_len += sizeof(int16);
            for (i=0; i<count; i++)
            {
                if (msg)sql_put_int(sizeof(int32), paramtypes[i], msg + msg_len);// Object ID of the data type of the parameter.
                msg_len += sizeof(int32);
            }
        }
        else
        {
            if (msg)    sql_put_int(sizeof(int16), 0, msg + msg_len);            // Many types of data specified parameter.
            msg_len += sizeof(int16);
        }
        msg_len ++;
        if (msg) break;   
        msg = (char *) malloc(msg_len);       
    }
    while (msg);
    sql_send_msg(sql_conn, 'P', msg_len, msg);

Le serveur me renvoie : Invalid byte sequence for encoding 'UTF8', This error can also happen if the byte sequence does not match the encoding exceped by the server, wich is controlled by 'clients_encoding'
Faut t'il que j'encode ma requete en UTF8 ?

Hors ligne

#5 24/06/2010 14:46:21

Marc Cousin
Membre

Re : Probleme de message Parse

Effectivement, j'ai lu un peu vite, msg continue à être le pointeur.

Pour ce qui est du retour, il signifie que dans un champ de type chaîne, une donnée qui était attendue en UTF8 n'était pas compatible. Donc il est possible que vous ayez besoin d'encoder la requête en utf8. Enfin les chaînes de caractère en paramètre.

Vous pouvez aussi modifier votre client_encoding, c'est probablement plus simple de laisser le serveur faire le travail.


Marc.

Hors ligne

#6 24/06/2010 15:01:18

Fooshi
Membre

Re : Probleme de message Parse

Faut 'il que j'encode tout le message en UTF-8 ou juste la requete passée en parametre ?
Faut 'il que rajoute juste un BOM (Marque d'ordre des octets) ou que je passe par une fonction d'encodage de caractere ?

Merci en tout cas de m'aider, ca fais plaisir !

Hors ligne

#7 24/06/2010 15:39:33

Marc Cousin
Membre

Re : Probleme de message Parse

Vous avez réellement de l'unicode ? Sinon, c'est vraiment plus simple de demander à la session d'être en LATIN9 par exemple.

Aucune idée pour le BOM. Je ne sais pas comment est implémenté l'UTF-8 dans le protocole bas niveau.

Pour ce qui est de l'encodage en UTF-8 du texte de la requête, cela ne devrait rien changer, puisque tous les mots clés SQL sont de l'ascii sur 7 bits. Sauf si vous avez mis des accents dans les noms d'objets…


Marc.

Hors ligne

#8 24/06/2010 15:48:16

gleu
Administrateur

Re : Probleme de message Parse

J'aimerais bien savoir ce que ça vous fait gagner (en temps d'exécution) par rapport à ce que ça vous fait perdre (en temps de codage, de maintenance, etc.).


Guillaume.

Hors ligne

Pied de page des forums