[R] BDD_Sqlite - Problème requête sql : base locked

Aide et conseils concernant AutoIt et ses outils.
Règles du forum
.
Avatar du membre
corrs78
Niveau 5
Niveau 5
Messages : 160
Enregistré le : lun. 13 août 2007 17:38
Localisation : Yvelines
Status : Hors ligne

Re: [R] BDD_Sqlite - Problème requête sql : base locked

#21

Message par corrs78 »

Bon, meme en mettant la fonction BtSetstat en debut de fonction, le problème persiste.
voilà ce que donne un "Consolewrite" de $CC:

Code : Tout sélectionner

$CC=2
$CC=3
$CC=4
$CC=5
$CC=4
$CC=3
$CC=2
$CC=1
$CC=2
$CC=3
$CC=4
$CC=5
$CC=4
$CC=3
$CC=2
$CC=1
$CC=2
$CC=3
$CC=4
$CC=5
[color=#FF0000]$CC=6[/color]
 
Et je pense que $CC peut aussi repasser à "0" car je perd l'accès aux boutons. ( j'ai ajouté un $GUI_HIDE si $CC = 0, c'est à dire, si l'on a une seule réponse à notre requête.)

on peut limiter la valeur d'une variable je suppose ?

Edit: Je pense avoir trouvé le moyen d’éviter cette erreur de dépassement de tableau:

Code : Tout sélectionner

        Case $msg = $BT_PRECEDENT [color=#0000FF]AND $CC > 1[/color]
            $CC -= 1 ; $CC = $CC - 1
            _recherche_motcle_next()
        Case $msg = $BT_SUIVANT  [color=#0000FF]AND $CC < $CC_MAX[/color]
            $CC += 1
            _recherche_motcle_next()
 
Avatar du membre
jchd
AutoIt MVPs (MVP)
AutoIt MVPs (MVP)
Messages : 2284
Enregistré le : lun. 30 mars 2009 22:57
Localisation : Sud-Ouest de la France (43.622788,-1.260864)
Status : Hors ligne

Re: [R] BDD_Sqlite - Problème requête sql : base locked

#22

Message par jchd »

Salut tout le monde,

Je n'ai plus guère de temps pour intervenir ici mais je ne peux m'empêcher de lire certains fils et celui-ci appelle un bon nombre de remarques.

@ tous,

Par pitié, n'employez plus la séquence Query, Fetch*, Finalize sauf avec grandes précautions et en sachant pourquoi vous y recourrez (et en testant _tous_ les codes erreur à chaque étape).
Remplacez ça par un Exec, QuerySingleRow, GetTable ou (ce qui est préférable) GetTable2d. Ensuite testez le code erreur. Ca simplifie votre code, ça va plus vite et ça gère correctement les erreurs.

@ corrs78

Ton approche risque fort de te causer des soucis insolubles : on ne doit jamais taper dans une base SQLite depuis un réseau. La faute n'en incombe pas à SQLite (qui est d'une très grande fiabilité) mais aux protocoles existants de partage de fichiers (aucun, sous aucun OS, ne fonctionne correctement dans tous les cas de figure, et on est en 2012 !).

Tu peux employer cette couche pour te mettre à l'abri de déconvenues cuisantes.

Ensuite, j'ai un souci de compréhension : tu fais tes recherches et surtout tes modifs sur une partie du nom OU du prénom. AMHA ça ne convient pas dans un cas réel simple.

Tartempion Jean-Jacques
DupontLaJoie Jacques

Avec une requête "Jacques" en modif, le résultat est douteux.

Le limit 1 est un tirage au sort, d'autant plus que SQL peut te retourner les rangs dans n'importe quel ordre, suivant l'implémentation. On n'est même pas sûrs que SQL te renvoie le même ordre dans deux SELECT identiques lancés l'un après l'autre.

Tu devrais utiliser les ID des rangs pour faire ce que tu veux et pas besoin de faire un compte avant. Qui plus est, dans un envonnement concurrentiel, ton approche amène à des situations que tu n'as pas prévu car tu n'utilises pas de transactions.

Pour ne pas bloquer la base, tu as plusieurs choix. Utiliser le mode WAL autorise concurrement UNE écriture (update, delete, ...) ET plusieurs lectures (select) sans blocage possible ni précautions particulières. Voir la doc sur le site SQLite à ce sujet. Le mode par défaut ne permet qu'une écriture OU plusieurs lectures simultanées.

Perso, je te conseille aussi de déclarer ID en INTEGER PRIMARY KEY AUTOINCREMENT (avec INTEGER en toutes lettres). Ainsi tu n'as pas besoin de faire saisir la valeur de l'ID. Ensuite, SQLite n'a pas de limitation en type et taille de contenu ; ton VARCHAR(40) équivaut à TEXT.

Tu n'as pas à "escaper" une valeur numérique (insert ou update ID), mais encore serait-il bon de s'assurer que cette valeur est numérique et n'existe pas déjà dans la base (fct ajout qui part à dame sinon). Et là aussi, transaction !

Tu devrais créer ton propre mécanisme de réservation de rangées pour qu'un poste puisse se réserver les Tartempion sans bloquer toute la base. La bonne solution passe par une table Opérations qui contient un ID d'opération en cours et une date/heure d'expiration (si un PC plante ou que l'appli reste trop longtemps "les pattes en l'air"). Tu mets l'OpId dans une colonne de ta table Utilisateurs et tu fais tes update et select en conditionnant sur l'OpId. Un trigger sur création d'une nouvelle opération fera le ménage des opérations expirées et un autre trigger répercutera l'expiration en remettant à 0 l'OpID dans la table Utilisateurs.

Maintenant côté pratique, je doute qu'un simple LIKE sur noms et prénoms fasse le boulot en exploitation. Même si tu n'as que des noms à script latin, un e ne sera jamais LIKE un é. J'ai écris une extension pour regrouper un bon nombre de fonctions Unicode, dont une recherche floue. Tu peux télécharger librement ici.

Le chargement d'extension se fait de préférence via cette UDF :
SQLiteExtLoad.au3
(4.8 Kio) Téléchargé 103 fois
Une autre possibilité est d'employer une table FTS3 (plutôt FTS4) pour y stocker une copie en minuscules désaccentuées des champs sur lesquels peuvent porter une recherche. FTS3/4 supporte l'extension ICU (full Unicode) mais ICU lui-même est un monstre de 18Mib plutôt lent. A toi de voir.

Dernière chose à laquelle je pense : juste après l'ouverture et la connection, lance
_SQLite_SetTimeout($hADB, 600000)
ce qui met un timeout de 10 minutes sur toute opération faite sur ta base ; en parallèle, utilise des transactions immédiates. Tu n'auras jamais de _SQLITE_BUSY ou _LOCKED.
Fichiers joints
SQLiteExtensions.au3
(4.31 Kio) Téléchargé 59 fois
La cryptographie d'aujourd'hui c'est le taquin plus l'électricité.
Avatar du membre
jchd
AutoIt MVPs (MVP)
AutoIt MVPs (MVP)
Messages : 2284
Enregistré le : lun. 30 mars 2009 22:57
Localisation : Sud-Ouest de la France (43.622788,-1.260864)
Status : Hors ligne

Re: [R] BDD_Sqlite - Problème requête sql : base locked

#23

Message par jchd »

Suite du long bidule d'au-dessus.

Le second fichier joint est une erreur de manip, mais il illustre quelques points (chargement d'extension, utilisation de mon UDF SQLite backup). Je ne suis pas sur ma machine de dév et TeamViewer plante souvent à cause d'une liaison trop lente. C'est bien la campagne mais ça a aussi ses limites !

Autre chose que j'ai cru voir : tu fais des GUICreateLabel à répétition. Ce n'est pas la bonne méthode. Tu dois créer ton label, éventuellement vide, stocker son ID et ensuite faire un SetData sur cet ID avec le texte désiré.
La cryptographie d'aujourd'hui c'est le taquin plus l'électricité.
Avatar du membre
corrs78
Niveau 5
Niveau 5
Messages : 160
Enregistré le : lun. 13 août 2007 17:38
Localisation : Yvelines
Status : Hors ligne

Re: [R] BDD_Sqlite - Problème requête sql : base locked

#24

Message par corrs78 »

Bonsoir Jchd,

J'essaierai de répondre à tous les points que tu as relevé dés demain.
En attendant, sache qu'une partie de ces incohérences ne sont pas dans mon projet final.
En effet, j'avais codé ce petit script pour mettre en évidence mon soucis de base locked du à ma 2ème boucle infinie qui n'avait rien a faire la.
Par exemple, j 'ai bien créé ma bdd avec un id unique integer, et c'est la dessus que je fais mes recherches ou mes motifs,
"Like %motcle%" where &id = id"

Pour le limit, je ne vois pas ou est le problème, car les résultats sont classés chronologiquement par rapport à l'Id (enfin je suppose)
Faudrait-il ajouter un order Desc ?

Pour finir, Je n'ai pas saisi le Timeout. Je pensais au contraire que c'était le temps que la base restait ouverte afin que la requête arrive à terme.

La BDD que je réalise est très simple car elle ne contient qu'une seule table. D'ailleurs elle n'est pas vouée à recevoir de multiples connexions. Seulement, j'ai ajouté une option qui permet de déplacer le chemin du fichier sqlite. Et j'ai essayé, maintenant qu'il y a des sqlqueryfinalyse partout, ça fonctionne à merveille. ( pour 2 utilisateurs). Mais il est vrai que pour une base plus grosse et sensée fonctionner en réseau, je m'orienterai plus sur lUDF Mysql.



Je suis ravi qu'un connaisseur du Sql vienne se joindre au Topic.

À suivre....
Avatar du membre
jchd
AutoIt MVPs (MVP)
AutoIt MVPs (MVP)
Messages : 2284
Enregistré le : lun. 30 mars 2009 22:57
Localisation : Sud-Ouest de la France (43.622788,-1.260864)
Status : Hors ligne

Re: [R] BDD_Sqlite - Problème requête sql : base locked

#25

Message par jchd »

Pas de multiples connexions mais deux utilisateurs ? Cela me semble contradictoire.
Si tu tapes dans ta base via le réseau et sans autres précautions, tu auras des problèmes un jour ou l'autre.

Le resultset n'est _jamais_ ordonné sauf emploi d'une clause ORDER BY. C'est SQL qui veut ça. Reposer sur l'assertion fausse que la pratique semble te donner raison est suicidaire, applicativement parlant. SQL manipule des ensembles et un ensemble n'est pas ordonné de par lui-même, bien qu'on puisse définir ou forcer une relation d'ordre total sur ses éléments. Ainsi, par exemple, je peux parler de l'ensemble des entiers naturels ℕ et plaquer dessus la relation d'ordre total (débile mais valide) ⍄ définie par :
o) tout entier pair est inférieur à tout entier impair
o) les entiers pairs sont ordonnés par la relation > (au sens habituel)
o) les entiers impairs sont ordonnés par la relation < (au sens habituel)

Du coup, l'ordre du sous-ensemble {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} par ⍄ est {0, 2, 4, 6, 8, 9, 7, 5, 3, 1}.

De la même manière, un moteur SQL conforme (comme SQLite) est parfaitement libre de te renvoyer le resultat d'un select dans un ordre arbitraire et pas forcément consistant.

Maintenant, je ne comprends pas ton exemple : "Like %motcle%" where &id = id"
Le LIKE est de trop !

Pour le timeout : par défaut, une connexion te renvoie BUSY immédiatement si la base est lockée par une autre connexion. Définir un timeout permet de faire attendre SQLite jusqu'à ce que la base soit de nouveau libre, ou expiration du délai. Sans rentrer dans des détails sordides, si tu pars du principe que toute transaction doit à un moment quelconque se terminer, il te faut définir ce timeout (en ms) comme "un temps supérieur à toute séquence possible de transactions concurrentes". Tout ça parce que SQLite est "serverless" et ne maintient pas une file d'attente des requêtes.

Pour que ce modèle de séquencement fonctionne, il suffit d'englober tout groupe de requête RMW (read, modify, write) dans une transaction immédiate (Begin immediate) et COMMIT ou ROLLBACK.

Ce n'est pas parce que ton schéma est simple que les interactions en contexte multi-utilisateurs le sont. La simplicité du schéma ne peut donner qu'une simplification des requêtes, et seulement si le schéma n'est pas inadapté.
La cryptographie d'aujourd'hui c'est le taquin plus l'électricité.
Répondre