Désactivez les validations explicites dans JDBC, détectez-les dans SQL ou mettez la base de données en lecture seule


12

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!


Il convient de mentionner - j'ai également effectué de nombreuses recherches sur les déclencheurs de "pré-validation". Il semble que ceux-ci n'existent pas, donc malheureusement ce n'est pas une option non plus.
Jake Feasel

2
Pour Oracle, cela semble être une bonne façon sournoise d'attraper des COMMIT: stackoverflow.com/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 arrêter la 2e situation en cours.
Philᵀᴹ

@Phil le seul problème est que je n'ai pas (et ne veux pas vraiment) de contrôle sur la définition de chacune des tables (celles-ci sont définies dans le panneau de gauche). Pour que la clause DEFERRABLE INITIALLY DEFERRED ne soit pas là (sauf s'il existe un moyen de le faire automatiquement pour toutes les tables - par exemple via un déclencheur système qui répond pour créer des instructions de table? Ugh)
Jake Feasel

1
@NickChammas J'ai besoin de désactiver les validations pour pouvoir conserver le schéma (tel que défini par le panneau de gauche) dans un état fixe. Il peut y avoir un certain nombre de personnes écrivant des requêtes sur le même schéma essayant de résoudre le même problème. Pour éviter qu'ils n'interfèrent les uns avec les autres, je dois m'assurer de ne pas modifier la structure et les données. Cela se fait via des transactions annulées, mais cela ne se produit pas si le code de droite est validé.
Jake Feasel

2
@RickJames DDL crée des validations implicites dans MySQL et Oracle, mais pas dans PostgreSQL ou SQL Server. Les mécanismes que j'ai mis en place à la suite de ce post gèrent cette préoccupation. En ce qui concerne la saisie de SQL arbitraire - c'est tout l'intérêt!
Jake Feasel

Réponses:


3

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.


Super, merci encore Phil. J'ai pu faire bon usage de cette technique pour Oracle. Cela me fait souhaiter que d'autres bases de données supportent des contraintes différées.
Jake Feasel

Pas de soucis. Passez au chat et dites bonjour :)
Philᵀᴹ
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.