Contexte : Je travaille sur http://sqlfiddle.com (mon site) et j'essaie d'empêcher une avenue d'abus possible là-bas. J'espère qu'en posant des questions sur un problème que j'aborde actuellement, je n'aggrave pas par inadvertance l'abus potentiel, mais que pouvez-vous faire? Je vous fais confiance.
Je voudrais empêcher tout utilisateur d'émettre des appels explicites de «validation» dans un bloc de transaction donné. Dans le contexte de SQL Fiddle, le bloc de transaction est le code qui est exécuté sur le panneau de droite. Fondamentalement, je fais une boucle et exécute une liste de commandes SQL en texte brut, et je veux m'assurer que toutes les modifications qu'elles apportent seront annulées à la fin du lot. Normalement, leurs modifications sont annulées, mais parfois il y a une déclaration explicite de «validation» dans le texte, et donc bien sûr, ma restauration ne fonctionnera pas. Cette validation explicite est très probable si un utilisateur tente de casser le schéma sur SQL Fiddle, donc les autres personnes qui y travaillent verront des erreurs.
Résultat principal souhaité : je voudrais désactiver les validations explicites au niveau JDBC, si possible. C'est parce que je dois prendre en charge plusieurs fournisseurs de backend de base de données, et bien sûr, chacun a ses caprices au bas niveau.
Option de secours : s'il n'est pas possible de configurer JDBC pour désactiver les validations explicites, je serais ouvert à des solutions pour détecter les validations explicites lors du traitement d'un lot pour chacun des backends suivants: SQL Server, Oracle, MySQL et PostgreSQL.
Pour SQL Server, j'ai pensé à cette solution: analyser le plan de requête XML pour l'instruction avant de l'exécuter et vérifier la présence d'une entrée correspondant à ce XPath:
//*[@StatementType="COMMIT TRANSACTION"]
Je pense que cela fonctionnerait assez bien pour SQL Server. Cependant, cette approche ne fonctionne pas pour les autres types de bases de données. La sortie du plan d'exécution XML d'Oracle pour les validations explicites ne fait aucune référence au fait que vous exécutez une instruction de validation (mais répète plutôt simplement la sortie du plan d'exécution des requêtes qu'elle est en train de valider). PostgreSQL et MySQL ne fournissent aucune sortie de plan d'exécution (XML ou autre) pour les validations explicites.
Cela me laisse avec la vérification de la déclaration réelle pour le mot «commit». Cela fonctionnerait, sauf qu'il peut y avoir toutes sortes de variations possibles:
declare @sql varchar(50)
set @sql = 'com' + 'mit'
exec(@sql);
Ce qui précède est un exemple pour SQL Server (que je pourrais contourner), mais je suppose que des choses similaires seraient possibles pour Oracle, MySQL et PostgreSQL. Ai-je tort sur cette hypothèse? Peut-être qu'ils n'autoriseraient pas les instructions de validation "dynamiques"? N'hésitez pas à utiliser SQL Fiddle (de préférence pas l'exemple de schéma ou quelqu'un d'autre est susceptible de travailler) pour voir si vous pouvez faire quelque chose de similaire dans Oracle, MySQL et PostgreSQL. Sinon, une simple détection de chaîne pourrait fonctionner pour ceux-ci.
Encore une autre possibilité
Une autre option m'est venue à l'esprit - si vous connaissez un moyen de définir l'une de ces bases de données en mode lecture seule, par exemple, alors que dans ce mode rien ne pourrait être validé, cela pourrait aussi fonctionner. Je devrais encore autoriser le démarrage des transactions et l'exécution de code en leur sein, tant que rien ne pourrait être validé dans ce mode. Est-ce possible?
Mise à jour
Ce que j'ai appris récemment - ce n'est en fait pas un problème avec PostgreSQL. Apparemment, les validations émises dans un bloc de transaction ne s'appliqueront pas si ce même bloc est finalement annulé (dans Postgres). Alors hourra pour Postgres!
Grâce au lien de Phil vers la publication SO, je pense que je peux utiliser le hack DEFERRABLE INITIALLY DEFERRED pour Oracle pour accomplir ce que je recherche (une erreur sera levée si un commit est émis, mais je peux contourner ce problème). Cela devrait concerner Oracle. (J'ai pensé un instant que les transactions imbriquées pourraient fonctionner ici, mais il ne semble pas qu'Oracle prend en charge les transactions imbriquées? Quoi qu'il en soit, je n'ai rien trouvé qui fonctionne de cette façon).
Je n'ai pas encore vraiment de solution pour MySQL. Essayé à l'aide de transactions imbriquées, mais cela ne semble pas fonctionner. Je pense sérieusement à des approches plus drastiques pour MySQL, telles que soit de ne rien autoriser sauf SELECT sur le côté droit ou de supprimer / recréer la base de données après chaque requête. Cependant, ni l'un ni l'autre ne sonnent bien.
Résolution
J'ai donc implémenté les solutions décrites pour SQL Server et Oracle, et comme je l'ai mentionné, ce n'est pas vraiment un problème pour PostgreSQL. Pour MySQL, j'ai pris la mesure quelque peu malheureuse de restreindre le panneau de requête pour sélectionner uniquement les instructions. DDL et DML pour MySQL devront simplement être entrés dans le panneau de schéma (le côté gauche). J'espère que cela ne casse pas trop de vieux violons, mais je pense que c'est simplement ce qui doit être fait pour assurer la cohérence des données. Merci!
la source
Réponses:
Pour Oracle, cela semble être une bonne façon sournoise d'attraper des COMMIT:
/programming//a/6463800/790702
Ce qu'il ne mentionne pas, c'est que vous devriez également pouvoir détecter la violation de contrainte dans votre code, pour empêcher la deuxième situation de se produire.
la source