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

C Discussion :

Insertion données avec caractères accentués dans DB MySQL


Sujet :

C

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Collégien
    Inscrit en
    Avril 2021
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Collégien

    Informations forums :
    Inscription : Avril 2021
    Messages : 3
    Points : 1
    Points
    1
    Par défaut Insertion données avec caractères accentués dans DB MySQL
    Bonsoir !

    J'essaie d'insérer une ligne d'enregistrement dans une base de données MySQL 5.7 via un programme écrit en C.

    Dans ce programme écrit en C, je demande à l'utilisateur d'entrer les différentes données de l'enregistrement.

    La requête se construit et doit être envoyée à la DB via l'API MySQL.

    Mais j'ai beau avoir essayé plusieurs solutions pour résoudre l'insertion de données avec caractères accentués, je n'y arrive vraiment pas.

    Il y a à chaque fois une erreur, quelle que soit la solution utilisée...

    Sous Linux, il n'y a pas ce souci. Tout fonctionne très bien avec des chars.

    Par contre, sous Windows, c'est une tout autre histoire... C'est sous cet OS que le problème se pose.

    J'utilise Visual Studio Community.

    Avez-vous une solution viable à me proposer ?

    Merci à tous !

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 629
    Points : 10 554
    Points
    10 554
    Par défaut
    Il faut + de précisions

    Mais si tu utilises les lignes de commandes, sous Windows et Linux, l'encodage est différent. Respectivement "codepage" OEM et UTF-8
    Quoique depuis Windows 10 version 1803, Windows permet de choisir l'UTF-8 pour remplacer l'ANSI/ les "codepages" OEM.

    Ensuite, cela va dépendre également :
    • du type de caractères que tu vas utiliser en C : char pour l'ASCI, unsigned char pour l'UTF-8, wchar_t pour l'UTF-16. Voire des types spécifiques imposés par 1 bibliothèque
    • l'encodage de ta base de données/ de ta table. Peut-être également la collation.

  3. #3
    Nouveau Candidat au Club
    Homme Profil pro
    Collégien
    Inscrit en
    Avril 2021
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Collégien

    Informations forums :
    Inscription : Avril 2021
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Effectivement, je suis en ligne de commande

    J'ai déjà utilisé wchar_t dans d'autres programmes en C.

    Du coup, j'ai tout passé en wchar_t (et j'ai adapté les fonctions à utiliser en conséquence).

    Il y a 2 problèmes maintenant :
    • Ma fonction qui vérifie s'il y a une quote dans chacune de mes données et qui l'échappe semble provoquer une corruption du HEAP lorsque je fais le free de mes données à la fin de mon main.
    • Si je désactive momentanément l'utilisation de cette fonction, les caractères accentués ne s'affichent pas correctement dans la base de données (je vois un ? dans un carré à la place du caractère accentué).

    Ma base de données et mes tables sont en UTF-8.

    J'utilise la fonction wcstombs pour convertir ma requête wchar_t UTF-16 en une requête char UTF-8 car la fonction mysql_query demande une requête en const char * en paramètre.

    Voici les 3 fichiers de mon code :
    https://pastebin.com/D42ArnNu
    https://pastebin.com/Z8WxjUHS
    https://pastebin.com/1XCgcmpK

    Ma DB de test :
    https://pastebin.com/y1UPcFvg

  4. #4
    Nouveau Candidat au Club
    Homme Profil pro
    Collégien
    Inscrit en
    Avril 2021
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Collégien

    Informations forums :
    Inscription : Avril 2021
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Pour le HEAP corrompu, je pense avoir résolu ce problème-là.

    Dans le 2ème fichier de code (https://pastebin.com/9D7XrBEY - aux lignes 31, 81 et 111), j'ai modifié pour faire un sizeof(wchar_t) * ce qu'il y a déjà pour le 2ème paramètre pour mes mallocs/reallocs.

    Ce problème-là semble résolu.

    Il reste le problème des caractères accentués à résoudre.

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 629
    Points : 10 554
    Points
    10 554
    Par défaut
    Je n'ai fait que lire mais ton code est spécifique
    • pas besoin de return à la toute fin pour les procédures (fonction qui retourne void)
    • pas besoin de parenthèser les retours (comme return (EXIT_SUCCESS);)
    • tu peux utiliser le pointeur pour changer les caractères, au lieu d'utiliser la syntaxe tableau
    • il me semble que tu as la fonction wprintf


    Et ensuite de ce que j'ai vu
    • ton code qui gère les problèmes d'allocation ne quitte pas la fonction. Donc si tu as 1 allocation NULL, ta fonction continue et cela doit crasher.
    • tu oublies d'ajouter le caractères sentinelle '\0' dans ta fonction DemandeChaineCaracteres. Tes corruptions peuvent venir de là : les fonctions basées sur le caractère '\0' débordent.
    • realloc se comporte comme 1 malloc si ta variable est NULL (<- la première fois en gros)
    • Dans ta fonction VerifierEtAjouterQuote, tu alloues 1 chaîne de caractères de char puisque tu ne précises pas le sizeof (*)
    • Dans ta fonction VerifierEtAjouterQuote, pour compter le nombre de quotes, tu devrais t'arrêter au caractère '\0'.
    • À vérifier : mais tu testes des wchar_t avec de simples char ('\'', '\0' par exemple), techniquement cela peut foirer


    * : D'après ce que tu écris, cela veut dire que tes caractères accentués sont reconnus lorsqu'ils sont castés en char

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Bonjour

    Il faut faire attention au realloc car si le realloc ne se passe pas, tu perds le pointeur de départ (qui avait lui été alloué et que tu ne peux désormais plus libérer)

    En fait, au lieu d'écrire pt=realloc(pt, ...) il te faut écrire tmp=realloc(pt, ...) puis, si realloc a réussi, écrire alors pt=tmp.
    Je ne vois pas trop l'utilité d'écrire une fonction void à laquelle on passe l'adresse du pointeur qui sera alloué. Je verrais mieux une fonction qui ne reçoit rien et qui alloue le pointeur, le remplit et renvoie le pointeur alloué. Déjà tu t'embêtes plus avec cette double indirection.
    Et il faut aussi penser à ce qui se passe si le buffer ne contient rien => dans ce cas, renvoyer une chaine vide

    Bref voilà comment j'écrirais cette fonction
    Code c : 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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    wchar_t *DemandeChaineCaracteres() {
    	// Déclaration de variable(s)
    	size_t dAlloc=0;
    	size_t dPosition=0
    	wchar_t *pChaine=NULL;
    	wchar_t cCaract;
    	wchar_t *pt;
     
    	// Pour être sûr d'allouer ne serait-ce qu'une chaine vide
    	while (1) {
    		// Si on a atteint la taille maximale de la chaine de caractères (ce qui arrive la première fois quand dPosition=dAlloc=0)
    		if (dPosition == dAlloc) {
    			// on réalloue dynamiquement pour l'augmenter (si pChaine=NULL le realloc se comporte comme malloc)
    			dAlloc+=50;				// On peut mettre ce 50 en macro plutôt qu'en variable, ça évite de bouffer de la RAM pour que dalle (on dirait que tu bosses chez Micro$oft)...
    			wchar_t *tmp=realloc(pChaine, sizeof(*tmp)*dAlloc);
    			if (tmp == NULL) {
    				free(pChaine);			// Fonctionne même si pChaine est à NULL
    				AfficherMessageQuandReallocationNotOkChaineCaracteres(); // Lui il pourrait être sorti de cette fonction pour être mis dans la fonction appelante
    				return NULL;
    			}
    			pChaine=tmp;
     
    			// On place/replace le pointeur à la position de la nouvelle chaine
    			pt=pChaine + dPosition;
    		}
     
     		// Lecture buffer
    		cCaract=getwchar();
     
    		// Si on a fini, on sort de la boucle (le '\0' sera mis à la fin)
    		if (cCaract == '\n' || cCaract == 0) break;
     
    		// On insère le caractère lu à la bonne position
    		// On avance d'une position
    		*pt=cCaract;
    		dPostion++;
    		pt++;
    	}
     
    	// La fin de la chaine
    	*pt='\0';
    	return pChaine;
    }

    Comme ça, l'appelant, au lieu d'écrire wchar_t *pChaine; DemandeChaineCaracteres(&pChaine) il écrit plus simplement wchar_t *pChaine=DemandeChaineCaracteres().
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 629
    Points : 10 554
    Points
    10 554
    Par défaut
    Après tests, on peut mettre L devant 1 chaîne de caractères, mais aussi devant 1 caractère (pour spécifier que c'est de l'UTF-16)
    Donc, comme je l'ai mentionné, je pense qu'on devrait utiliser (même dans le code de @Sve@r) les caractères L'\0', L'\'', L'\n' par exemple.
    Mais je ne sais pas si cela change quelque chose

    Et pour ton histoire d'échappement, cela fonctionne nickel, je ne comprends pas d'où cela peut provenir
    1 code avec quelques tests succincts. Attention : on ne peut pas mixer printf et wprintf. C'est soit l'1 soit l'autre
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    #include <stdio.h>
    #include <stdlib.h>
    #include <wchar.h>
     
     
    /*****************************************************************************/
    /***********************************  Main  **********************************/
    /*****************************************************************************/
     
    void UTF_16_display_hexa(wchar_t* str, char* end_str) {
        if (str != NULL) {
            size_t len = wcslen(str);
     
            if (len > 0) {
                size_t c;
                wchar_t* str_c;
                unsigned char bit_hi, bit_lo;
     
                for(c=1, str_c=str; c <= len; ++c, ++str_c) {
                    bit_hi = (((*str_c) >> 8) & 0xFF);
                    bit_lo = ((*str_c) & 0xFF);
     
                    printf("%02X%02X%c", bit_hi, bit_lo, (((c % 8) != 0)? ' ': '\n'));
                }
            }
     
            if (end_str != NULL) { printf("%s", end_str); }
        }
    }
     
     
    wchar_t* UTF_16_escape(wchar_t* str) {
        wchar_t* escape_str;
     
        if (str != NULL) {
            size_t len, nb_quotes;
            wchar_t* str_c;
     
    //      Calculate len and nb_quotes
            str_c = str;
     
            len       = 0;
            nb_quotes = 0;
     
            while ((*str_c) != L'\0') {
                if ((*str_c) == L'\'') { ++nb_quotes; }
     
                ++str_c;
                ++len;
            }
     
            printf("UTF_16_escape - debug: len : %lu, nb_quotes : %lu\n", len, nb_quotes);
    //      wprintf(L"UTF_16_escape - debug: len : %lu, nb_quotes : %lu\n", len, nb_quotes);
     
            if (len > 0) {
    //          Allocate and copy/ escape
                escape_str = malloc(sizeof(wchar_t) * (len + nb_quotes + 1));
     
                if (escape_str != NULL) {
                    if (nb_quotes > 0) {
                        wchar_t* escape_str_c;
     
                        str_c        = str;
                        escape_str_c = escape_str;
     
                        len = 0;
     
                        while ((*str_c) != L'\0') {
                            if ((*str_c) == L'\'') {
                                (*escape_str_c) = L'\\';
                                ++escape_str_c;
                            }
     
                            (*escape_str_c) = (*str_c);
     
                            ++str_c;
                            ++escape_str_c;
                            ++len;
                        }
                    } else {
                        wcscpy(escape_str, str);
                    }
     
                    escape_str[(len + nb_quotes)] = L'\0';
                }
            } else {
                escape_str = NULL;
            }
        } else {
            escape_str = NULL;
        }
     
        return escape_str;
    }
     
     
    int main(int argc, char** argv)
    {
        wchar_t str_empty[] = L"";
        wchar_t str_01[] = L"Lorem ipsum dolor sit amet, consectetur adipiscing elit";
        wchar_t str_02[] = L"Le code &eacute permet d'écrire un é, &Eacute pour écrire É.";
        wchar_t str_03[] = L"\'\'\'\'\'\'\'''''''";
        wchar_t* escape_str_00;
        wchar_t* escape_str_01;
        wchar_t* escape_str_02;
        wchar_t* escape_str_03;
     
    //  wprintf(L"%ls\n%ls\n%ls\n%ls\n", str_empty, str_01, str_02, str_03);
        UTF_16_display_hexa(str_01, "\n\n");
        UTF_16_display_hexa(str_02, "\n\n");
        UTF_16_display_hexa(str_03, "\n\n");
     
        escape_str_00 = UTF_16_escape(str_empty);
        escape_str_01 = UTF_16_escape(str_01);
        escape_str_02 = UTF_16_escape(str_02);
        escape_str_03 = UTF_16_escape(str_03);
     
        printf("\n");
     
        if (escape_str_00 == NULL) { printf("main - debug: test empty ok\n"); }
        if (escape_str_01 != NULL) { printf("main - debug: test str_01 ok (len: %lu)\n", wcslen(escape_str_01)); }
        if (escape_str_02 != NULL) { printf("main - debug: test str_02 ok (len: %lu)\n", wcslen(escape_str_02)); }
        if (escape_str_03 != NULL) { printf("main - debug: test str_03 ok (len: %lu)\n", wcslen(escape_str_03)); }
     
        printf("\n");
     
    //  wprintf(L"%ls\n%ls\n%ls\n%ls\n", str_empty, escape_str_01, escape_str_02, escape_str_03);
        UTF_16_display_hexa(escape_str_01, "\n\n");
        UTF_16_display_hexa(escape_str_02, "\n\n");
        UTF_16_display_hexa(escape_str_03, "\n\n");
     
        if (escape_str_01 != NULL) { free(escape_str_01); }
        if (escape_str_02 != NULL) { free(escape_str_02); }
        if (escape_str_03 != NULL) { free(escape_str_03); }
     
        return EXIT_SUCCESS;
    }

  8. #8
    Membre éprouvé
    Femme Profil pro
    ..
    Inscrit en
    Décembre 2019
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 94
    Localisation : Autre

    Informations professionnelles :
    Activité : ..

    Informations forums :
    Inscription : Décembre 2019
    Messages : 562
    Points : 1 253
    Points
    1 253
    Par défaut
    Salut,

    Citation Envoyé par Portocolo951 Voir le message
    Sous Linux, il n'y a pas ce souci. Tout fonctionne très bien avec des chars.

    Par contre, sous Windows, c'est une tout autre histoire... C'est sous cet OS que le problème se pose.

    J'utilise Visual Studio Community.

    Avez-vous une solution viable à me proposer ?
    Tu restes en char, tu récupères ta ligne avec fgets(). Pour linux rien ne change. Pour windows tu ajoutes une étape pour convertir ta ligne en utf-8 avec MultiByteToWideChar() et WideCharToMultiByte.

Discussions similaires

  1. [MySQL] MySQL/PHP insertion de données avec clé étrangere dans un formulaire
    Par ApprentiOracle dans le forum PHP & Base de données
    Réponses: 9
    Dernier message: 23/02/2016, 14h37
  2. Réponses: 6
    Dernier message: 04/11/2013, 19h32
  3. [MySQL] Caractères accentués dans base de données MySQL
    Par enfin dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 11/01/2007, 20h54
  4. Problème d'INSERT avec caractères accentués: mysql 5.0
    Par yizashi dans le forum Installation
    Réponses: 2
    Dernier message: 05/04/2006, 10h26
  5. Chaines avec caractères accentués dans interbase
    Par Tsimplice dans le forum Bases de données
    Réponses: 4
    Dernier message: 08/03/2004, 17h12

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